题意:
有编号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 ",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)将其出队。