HDU 1535 Invitation Cards(SPFA,及其优化)

题意:

        有编号1~P的站点, 有Q条公交车路线,公交车路线只从一个起点站直接到达终点站,是单向的,每条路线有它自己的车费。

        有P个人早上从1出发,他们要到达每一个公交站点, 然后到了晚上再返回点1。 求所有人来回的最小费用之和。

思路:

       1.两次SPFA,也就是巧妙的将路线进行了翻转。

code 1:(数据较大,不能用二维数组,用的邻接表)

  1 #include <stdio.h>
  2 #include <string.h>
  3 #include <algorithm>
  4 #include <queue>
  5 using namespace std;
  6 #define MAXN 1000000
  7 #define INF  0x3f3f3f3f
  8 struct node
  9 {
 10     int now,to,w;
 11 }edge[MAXN];//记录每条边的信息,起始点,终止点,权值
 12 int first[MAXN],next[MAXN];
 13 int dis[MAXN],vis[MAXN];
 14 int n,m;
 15 void turnup()//反转图
 16 {
 17     int i,k;
 18     for(i = 0; i<=m; i++)
 19         first[i] = next[i] = -1;
 20     for(i = 0; i<m; i++)
 21     {
 22         k= edge[i].to;
 23         next[i] = first[k];
 24         first[k] = i;
 25     }
 26 }
 27 void SPFA2(int start)
 28 {
 29     int i;
 30     for(i = 0; i<=n; i++)
 31         dis[i] = INF;
 32     dis[start] = 0;
 33     memset(vis,0,sizeof(vis));
 34     queue<int> Q;
 35     Q.push(start);
 36     while(!Q.empty())
 37     {
 38         start = Q.front();
 39         Q.pop();
 40         vis[start] = 0;
 41         i = first[start];
 42         while(1)
 43         {
 44             int to = edge[i].now;
 45             if(dis[to]>dis[start]+edge[i].w)
 46             {
 47                 dis[to]=dis[start]+edge[i].w;
 48                 if(!vis[to])
 49                 {
 50                     vis[to] = 1;
 51                     Q.push(to);
 52                 }
 53             }
 54             i = next[i];
 55             if(i==-1)
 56                 break;
 57         }
 58     }
 59     return;
 60 }
 61 void SPFA1(int start)
 62 {
 63     int i;
 64     for(i = 0; i<=n; i++)
 65         dis[i] = INF;
 66     dis[start] = 0;
 67     memset(vis,0,sizeof(vis));
 68     queue<int> Q;
 69     Q.push(start);
 70     while(!Q.empty())
 71     {
 72         start = Q.front();
 73         Q.pop();
 74         vis[start] = 0;
 75         i=first[start];
 76         while(1)
 77         {
 78             int to = edge[i].to;
 79             if(dis[to]>dis[start]+edge[i].w)
 80             {
 81                 dis[to]=dis[start]+edge[i].w;
 82                 if(!vis[to])
 83                 {
 84                     vis[to] = 1;
 85                     Q.push(to);
 86                 }
 87             }
 88             i = next[i];
 89             if(i==-1)
 90                 break;
 91         }
 92     }
 93     return;
 94 }
 95 int main()
 96 {
 97     int t,sum,i;
 98     scanf("%d",&t);
 99     while(t--)
100     {
101         sum = 0;
102         scanf("%d%d",&n,&m);
103         for(i=0; i<m; i++)
104             first[i]=next[i]=-1;
105         for(i=0; i<m; i++)
106         {
107             scanf("%d%d%d",&edge[i].now,&edge[i].to,&edge[i].w);
108             next[i]=first[edge[i].now];
109             first[edge[i].now]=i;
110         }
111         SPFA1(1);
112         for(i = 2; i<=n; i++)
113             sum+=dis[i];
114         turnup();
115         SPFA2(1);
116         for(i = 2; i<=n; i++)
117             sum+=dis[i];
118         printf("%d\n",sum);
119     }
120     return 0;
121 }

 

这里SPFA 可以优化,关于SPFA的优化:

SLF:Small Label First 策略。

  实现方法是,设队首元素为 i,队列中要加入节点 j,在 dj<=di 时加到队首而不是队尾,否则和普通的 SPFA 一样加到队尾。

LLL:Large Label Last 策略。

  实现方法是,设队列 Q 中的队首元素为 i,距离标号的平均值为 avg(d),每次出队时,若 di>avg(d),把 i 移到队列末尾,如此反复,直到找到一个 i 使 ,di<=avg(d)将其出队。

posted @ 2014-07-24 10:06  PJQOOO  阅读(331)  评论(0编辑  收藏  举报