最短路。

感觉他讲的很不错。http://www.cnblogs.com/Yan-C/p/3916281.html

以下均从他的内容整理而来。

  1 //Bellman-ford
  2 //bellman-ford 算法解决的是一般情况下的单源最短路径问题,其边可以为负值。
  3 //bellman-ford算法可以判断图是否存在负环,若存在负环会返回一个布尔值。
  4 //当然在没有负环存在的情况下会返回所求的最短路径的值。
  5 //以hdu1874为例  http://acm.hdu.edu.cn/showproblem.php?pid=1874
  6 
  7 //     多组输入。第一行给你两个数n(代表点),m(代表边)
  8 
  9 //   第2—m+1行 ,每行三个数u,v,  w。0<=u,v<n,  w>=0;   【因为此图w>=0,所以是一定没有负环的】
 10 
 11 //   第m+2行两个数 s, t  。 s为源点,t为要到达的目的点。
 12 
 13 //   求s到t 的最短路,若存在最短路输出最短路的值,否则输出-1。
 14 /*
 15 #include<cstdio>
 16 #include<cstring>
 17 #include<iostream>
 18 #include<algorithm>
 19 using namespace std;
 20 
 21 const int maxn=9999999;
 22 int dis[210];  //保存最短路径
 23 
 24 //对于bellman-ford算法 推荐使用结构体数组存储
 25 struct node
 26 {
 27     int u,v,w;
 28 }edge[1010];
 29 
 30 
 31 int n,m,s,t;
 32 
 33 void Bellman()
 34 {
 35     bool flag=1;  //用于优化的
 36      //初始化
 37     for(int i=0;i<=n;i++)
 38         dis[i]=maxn;
 39     dis[s]=0;
 40     m=m<<1;  //此处和m = 2*m是一样的,因为建立的无向图
 41     for(int i=1;i<n;i++)
 42     {
 43         flag=0;
 44         for(int j=0;j<m;j++)
 45             if(dis[edge[j].v]>dis[edge[j].u]+edge[j].w)  //进行松弛操作
 46             {
 47                 dis[edge[j].v]=dis[edge[j].u]+edge[j].w;
 48                 flag=1;
 49             }
 50         if(!flag) break;
 51     }
 52     printf("%d
",dis[t]==maxn?-1:dis[t]);
 53 
 54 }
 55 int main()
 56 {
 57     while(scanf("%d%d",&n,&m)!=EOF)
 58     {
 59         for(int i=0;i<m;i++){
 60             scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].w);
 61             edge[i+m].u=edge[i].v;  //因为为无向图所以u—>v和v—>u 是一样的
 62             edge[i+m].v=edge[i].u;
 63             edge[i+m].w=edge[i].w;
 64         }
 65         scanf("%d%d",&s,&t);
 66         Bellman();
 67     }
 68 }
 69 */
 70 
 71 //以上是用来求最短路,,下面判断负环!!
 72 //以poj3259为例  http://poj.org/problem?id=3259
 73 
 74 //题目大意: 第一行 输入一个数  是表示几组测试数据
 75 
 76 //第二行  三个数 N(点的个数),M(正边的个数),W(负边的个数) 注意 :正边为双向的,负边为单向的。
 77 
 78 //然后 M行u,v,w;
 79 
 80 //再然后W行u,v,w;
 81 
 82 //求这个图是不是存在负环。 有 YES 没NO。
 83 
 84 /*
 85 #include<cstdio>
 86 #include<algorithm>
 87 #include<cstring>
 88 using namespace std;
 89 const int maxn=520;
 90 const int maxe=5600;
 91 const int maxx=99999999;
 92 struct node
 93 {
 94     int u,v,w;
 95 }edge[maxe];
 96 
 97 int n,m,w;
 98 
 99 int dis[520];
100 int Bellman ()
101 {
102     int flag=0;
103     for(int i=0;i<=n;i++)
104         dis[i]=maxx;
105     dis[1]=0;
106     int i;
107     for( i=0;i<n;i++)   //注意,,此处i从零开始,若没有负环i不会增到n-1;
108     {
109           flag=0;
110         for(int j=0;j<m;j++)
111         {
112 
113         if(dis[edge[j].v]>dis[edge[j].u]+edge[j].w)
114             {
115                 dis[edge[j].v]=dis[edge[j].u]+edge[j].w;
116                 flag=1;
117             }
118 
119         }
120         if(!flag) break;
121          if(i==n-1) return 1;
122     }
123     //if(i==n-1) printf("YES
");   //坑死!!!!!!
124       //  else puts("NO");
125         return 0;
126 }
127 
128 int main()
129 {
130     int t;
131     scanf("%d",&t);
132     while(t--)
133     {
134         scanf("%d%d%d",&n,&m,&w);
135         for(int i=0;i<m;i++)
136         {
137             scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].w);
138             edge[i+m].u=edge[i].v;
139             edge[i+m].v=edge[i].u;
140             edge[i+m].w=edge[i].w;
141         }
142         m=m<<1;
143         for(int i=m;i<w+m;i++)
144             {
145                 scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].w);
146                 edge[i].w=-edge[i].w;
147             }
148             m+=w;
149        if( Bellman()) puts("YES");
150         else puts("NO");
151     }
152     return 0;
153 }
154 
155 */
156 
157 //Dijkstra算法
158 //hdu1874
159 //朴素实现
160 /*
161 #include<iostream>
162 #include<cmath>
163 #include<cstdio>
164 #include<algorithm>
165 #include<cstring>
166 using namespace std;
167 const int N=200,M=1000;
168 int maxn=100000000;
169 int w[N][N],d[M];  //边权,最小数
170 int vis[N];//标记
171 int x,y,c,m,n,s,t;
172 int Dijkstra(int s,int t)
173 {
174 memset(vis,0,sizeof(vis));   //初始标记
175 for(int i=0;i<n;i++) d[i]=(i==s?0:maxn);  //初始s点距离为0,原点到其它点距离为无穷大
176     for(int i=0;i<n;i++)  {
177 int x,m=maxn;
178         for(int y=0;y<n;y++) if(!vis[y]&&d[y]<=m)  m=d[x=y];  //搜索上次的最短点到下一距离最短的未访问点,并把该点记为x;
179         vis[x]=1;//标记该店已访问
180         for(int y=0;y<n;y++) d[y]=min(d[y],d[x]+w[x][y]);//计算x到任意点y的最小距离:……或者上一点加边权
181     }
182     if(d[t]==maxn)return -1;
183     else return d[t];
184 }
185 
186 int main()
187 {
188     while(scanf("%d",&n)==1&&n)
189     { for(int i=0;i<n;i++)
190     for(int j=0;j<n;j++)            // memset(w,0,sizeof(w);
191         w[i][j]=maxn;
192         scanf("%d",&m);
193         for(int i=0;i<m;i++){
194             scanf("%d%d%d",&x,&y,&c);
195             w[x][y]=(w[x][y]==maxn?c:min(c,w[x][y]));
196             w[y][x]=w[x][y];
197         }
198         scanf("%d%d",&s,&t);
199         printf("%d
",Dijkstra(s,t));
200     }
201     return 0;
202 }
203 */
204 
205 //Dijkstra算法
206 //用链式前向星和优先队列实现
207 /*
208 #include <cstdio>
209 #include <cstring>
210 #include <algorithm>
211 #include <iostream>
212 #include <queue>
213 #define MAX 9999999
214 
215 using namespace std;
216 //pair 的first 保存的为最短距离, second保存的为顶点编号
217 typedef pair<int, int >P;//对组  不知道请自行百度
218 
219 struct node
220 {
221     int v, w;//v 为到达的点, w为权重
222     int next;//记录下一个结构体的位置 ,就向链表的next功能是一样的
223 };
224 node edge[2003];//存所有的边,因为是无向图,所以*2
225 int cnt;//结构体的下标
226 int n, s, t;//n 点数,s 起点,t止点
227 int head[203];//和链表的头指针数组是一样的。只不过此处head[u]记录的为最后加入 edge 的且与u相连的边在 edge 中的位置,即下标
228 
229 void add(int u, int v, int w)//加边操作
230 {
231     edge[cnt].v = v;
232     edge[cnt].w = w;
233     edge[cnt].next = head[u];//获得下一个结构体的位置
234     head[u] = cnt++;//记录头指针的下标
235 }
236 
237 void dijkstra()
238 {
239     int dis[203];//最短路径数组
240     int i, v;//v保存从队列中取出的数的第二个数  也就是 顶点的编号
241     priority_queue<P,vector<P>,greater<P> >que;//优先队列 从小到大
242     node e;//保存边的信息,为了书写方便
243     P p;//保存从队列取出的数值
244 
245     fill(dis,dis+n,MAX);//初始化,都为无穷大
246     dis[s] = 0;//s—>s  距离为0
247     que.push(P(0,s));//放入距离 为0   点为s
248     while(!que.empty()){
249         p = que.top();//取出队列中最短距离最小的对组
250         que.pop();//删除
251         v = p.second;//获得最短距离最小的顶点编号
252         if(dis[v] < p.first)//若取出的不是最短距离
253             continue;//则进行下一次循环
254         for(i=head[v];i!=-1;i=edge[i].next)//对与此点相连的所有的点进行遍历
255         {
256             e = edge[i];//为了书写的方便。
257             if(dis[e.v]>dis[v]+e.w){//进行松弛
258                 dis[e.v]=dis[v]+e.w;//松弛成功
259                 que.push(P(dis[e.v],e.v));//讲找到的松弛成功的距离 和顶点放入队列
260             }
261         }
262     }
263     printf("%d
",dis[t]==MAX?-1:dis[t]);//输出结果
264 }
265 
266 int main()
267 {
268     int m, u, v, w;
269 
270     while(scanf("%d %d",&n,&m)==2){//获取点数  边数
271         cnt = 0;//结构体下标从0开始
272         memset(head,-1,sizeof(head));//初始化head[N]数组
273         while(m--){
274             scanf("%d %d %d",&u,&v,&w);//获取u,v,w(u,v)
275             add(u,v,w);//加边
276             add(v,u,w);//加边
277         }
278         scanf("%d %d",&s,&t);//获取起止点
279         dijkstra();
280     }
281     return 0;
282 }
283 
284 */
285 
286 
287 //floyd-Warshall算法   时间复杂度较高O(n^3)
288 //  k i j  或者 i k j   不要写成 i j  k  和内存读取有关
289 /*
290 #include<cstdio>
291 #include<cstring>
292 #include<algorithm>
293 #include<cmath>
294 using namespace std;
295 int g[210][210];
296 int n,m,s,t;
297 const int maxn=99999999;
298 void floyd ()
299 {
300 
301     for(int k=0;k<n;k++)
302         for(int i=0;i<n;i++)
303             for(int j=0;j<n;j++)
304             g[i][j]=min(g[i][j],g[i][k]+g[k][j]);
305       printf("%d
",g[s][t]==maxn?-1:g[s][t]);
306 }
307 
308 int main()
309 {
310     int x,y,c;
311     while(scanf("%d%d",&n,&m)!=EOF)
312     {
313          for(int i=0;i<n;i++)
314             for(int j=0;j<n;j++)
315                 g[i][j]=(i==j?0:maxn);
316         for(int i=0;i<m;i++)
317             {
318                 scanf("%d%d%d",&x,&y,&c);
319                 g[y][x]=g[x][y]=(g[x][y]>c?c:g[x][y]);
320             }
321             scanf("%d%d",&s,&t);
322         floyd();
323     }
324     return 0;
325 }
326 */
327 
328 //SPFA算法   (bellman-ford算法的优化)
329 
330 //朴素实现
331 /*
332 #include <cstdio>
333 #include <cstring>
334 #include <algorithm>
335 #include <iostream>
336 #include <queue>
337 #define MAX 9999999
338 
339 using namespace std;
340 
341 int G[503][503];
342 int n;
343 
344 bool SPFA()
345 {
346     int u;//从队列Q中取出的数
347     int i;
348     queue<int >que;//Q队列
349     int dis[503];//保存最短距离
350     bool vis[503];//访问数组
351     int flag[503];//记录点进入队列的次数
352 
353     memset(flag,0,sizeof(flag));//初始化为0
354     memset(vis,false,sizeof(vis));//初始化
355     fill(dis,dis+n+1,MAX);//初始化
356     dis[1] = 0;//从  1 开始
357     que.push(1);//将 1 放入队列
358     while(!que.empty()){//Q 不为空
359         u = que.front();//从Q中取出一个数
360         que.pop();//删除此数
361         vis[u] = false;//标记为 未 访问过
362         for(i=1;i<=n;i++)//对所有的边
363         {
364             if(dis[i]>dis[u]+G[u][i]){//进行松弛
365                 dis[i] = dis[u]+G[u][i];//松弛成功
366                 if(!vis[i]){//若点i 未被访问过
367                     vis[i] = true;//标记为访问过
368                     flag[i]++;//入队列次数+1
369                     if(flag[i]>=n)//若此点进入队列此数超过n次  说明有负环
370                         return true;//有负环
371                     que.push(i);//将 此点放入队列
372                 }
373             }
374         }
375     }
376     return false;//没有负环
377 }
378 
379 int main()
380 {
381     int t, k, i, j, u, v, w, m;
382 
383     scanf("%d",&t);
384     while(t--){
385         scanf("%d %d %d",&n,&m,&k);
386         for(i=1;i<=n;i++)
387             for(j=1;j<=n;j++)
388                 G[i][j] = i==j?0:MAX;
389         for(i=0;i<m;i++)
390         {
391             scanf("%d %d %d",&u,&v,&w);
392             if(G[u][v]>w)
393                 G[u][v] = G[v][u] = w;
394         }
395         for(i=0;i<k;i++)
396         {
397             scanf("%d %d %d",&u,&v,&w);
398             G[u][v] = -w;
399         }
400         printf("%s
",SPFA()?"YES":"NO");
401     }
402     return 0;
403 }
404 
405 */
406 
407 //SPFA算法对于稀疏图才能发挥它的大作用,对于稀疏图用  前向星
408 //下面就是 SPFA+前向星的程序  并应用了SLF  双向队列进行优化
409 
410 /*
411 #include <cstdio>
412 #include <cstring>
413 #include <algorithm>
414 #include <iostream>
415 #include <queue>
416 #define MAX 9999999
417 
418 using namespace std;
419 
420 struct node//前向星
421 {
422     int v,w;//v 终点,w 权值
423     int next;//下一个
424 };
425 node edge[5203];//前向星
426 int head[503];//头指针式的数组
427 int cnt;//下标
428 int n;//点的个数
429 
430 void add(int u, int v, int w)//加边  建议 若看不懂前向星 请自己动手画一下 按照给出的数据和程序
431 {
432     edge[cnt].v = v;//
433     edge[cnt].w = w;//
434     edge[cnt].next = head[u];//
435     head[u] = cnt++;//
436 }
437 
438 bool SPFA()
439 {
440     int i, u, v;//u 从Q中取出的点  v找到的点
441     int dis[503];//保存最短路径
442     int flag[503];//保存某点加入队列的次数
443     bool vis[503];//标记数组
444     deque<int>que;//双向队列  自己百度
445 
446     fill(dis,dis+n+1,MAX);//初始化
447     memset(flag,0,sizeof(flag));//初始化
448     memset(vis,false,sizeof(vis));//初始化
449     dis[1] = 0;// s为1
450     que.push_back(1);//将s = 1 加入队列
451     while(!que.empty()){//当队列不为空
452         u = que.front();//从队列中取出一个数
453         que.pop_front();//删除
454         vis[u] = false;//标记为未访问
455         for(i=head[u];i!=-1;i=edge[i].next)//对所有与该边相连的边进行查找
456         {
457             v = edge[i].v;//保存点 便于操作
458             if(dis[v]>dis[u]+edge[i].w){//进行松弛操作
459                 dis[v] = dis[u]+edge[i].w;//松弛成功
460                 if(!vis[v]){//若该点未被标记
461                     vis[v] = true;//标记为真
462                     flag[v]++;//该点入队列次数++
463                     if(flag[v]>=n)//若该点进入队列次数超过n次 说明有负环
464                         return true;//返回有负环
465                     //一下为SLF优化
466                     if(!que.empty() && dis[v]<dis[que.front()])//若为队列不为空 && 队列第一个点的最短距离大于当前点的最短距离
467                         que.push_front(v);//将该点放到队首
468                     else//不然
469                         que.push_back(v);//放入队尾
470                 }
471             }
472         }
473     }
474     return false;//没有负环
475 }
476 
477 int main()
478 {
479     int u, v, w, m, k, t;
480 
481     scanf("%d",&t);//获取测试数据
482     while(t--){
483         memset(head,-1,sizeof(head));//初始化
484         cnt = 0;//下标为0  初始化
485         scanf("%d %d %d",&n,&m,&k);//获取点的个数 ,正边的个数, 负边的个数
486         while(m--){
487             scanf("%d %d %d",&u,&v,&w);//正边获取
488             add(u,v,w);//无向图
489             add(v,u,w);//双向建图
490         }
491         while(k--){
492             scanf("%d %d %d",&u,&v,&w);
493             add(u,v,-w);//单向图
494         }
495         printf("%s
",SPFA()?"YES":"NO");//输出结果
496     }
497     return 0;
498 }
499 
500 */
501 
502 
503 // BFS 求解最短路
504 //hdu1874
505 /*
506 #include <algorithm>
507 #include <iostream>
508 #include <cstdio>
509 #include <cstring>
510 #include <queue>
511 
512 using namespace std;
513 
514 struct P
515 {
516     int v, w;//v 顶点 w 最短距离
517     bool operator <(const P &a)const{
518         return a.w < w;//按w  从小到大排序
519     }
520 };
521 struct node//前向星
522 {
523     int v, w;//v 顶点  w权重
524     int next;//下一个位置
525 };
526 node edge[2003];
527 int head[203];//头指针数组
528 int cnt, s, t;// cnt 下标
529 
530 void add(int u, int v, int w)//加边操作
531 {
532     edge[cnt].v = v;
533     edge[cnt].w = w;
534     edge[cnt].next = head[u];
535     head[u] = cnt++;
536 }
537 
538 void BFS()
539 {
540     priority_queue<P>que;//优先队列   按w从小到大
541     bool vis[203];//标记数组, 标记是否被访问过
542     P p, q;
543     int i, v;
544 
545     memset(vis,false,sizeof(vis));//初始化
546     p.v = s;//顶点为 s
547     p.w = 0;//距离为 0
548     que.push(p);//放入队列
549     while(que.empty() == false){//队列不为空
550         p = que.top();//取出队列的队首
551         que.pop();//删除
552         if(p.v == t){//若找到终点
553             printf("%d
",p.w);//输出结果
554             return ;//返回
555         }
556         vis[p.v] = true;//此点标记为访问过
557         for(i=head[p.v];i!=-1;i=edge[i].next)//查找与该点相连的点
558         {
559             v = edge[i].v;
560             if(vis[v] == false){//若点未被访问过
561                 q.v = v;//存入结构体
562                 q.w = p.w+edge[i].w;//距离更新
563                 que.push(q);//放入队列
564             }
565         }
566     }
567     printf("-1
");//若没有到达终点  输出-1
568 }
569 
570 int main()
571 {
572     int m, u, v, w, n;
573 
574     while(scanf("%d %d",&n,&m)==2){//获取点的个数  边的个数
575         memset(head,-1,sizeof(head));//初始化
576         cnt = 0;//初始化
577         while(m--){
578             scanf("%d %d %d",&u,&v,&w);//获取u,v,w
579             add(u,v,w);//加边
580             add(v,u,w);//无向图   双向加边
581         }
582         scanf("%d %d",&s,&t);//获取起止点
583         BFS();
584     }
585     return 0;
586 }
587 
588 */
589 
590 // 路径还原
591 /*
592 #include <algorithm>
593 #include <iostream>
594 #include <cstdio>
595 #include <cstring>
596 #include <queue>
597 #define INF 999999
598 using namespace std;
599 
600 int G[203][203];
601 int n, s, t;
602 
603 bool Dijkstra()
604 {
605     int i, j, k;
606     int dis[203];
607     bool vis[203];
608     int pre[203];//记录路径
609 
610     memset(vis,false,sizeof(vis));
611     fill(dis,dis+n,INF);
612     memset(pre,-1,sizeof(pre));//初始化为-1
613     dis[s] = 0;
614     for(i=0;i<n;i++)
615     {
616         k = -1;
617         for(j=0;j<n;j++)
618             if(vis[j] == false && (k == -1 || dis[k]>dis[j]))
619                 k = j;
620         if(k == -1)
621             break;
622         vis[k] = true;
623         for(j=0;j<n;j++)
624             if(vis[j] == false && dis[j]>dis[k]+G[k][j]){
625                 dis[j] = dis[k]+G[k][j];
626                 pre[j] = k;//在松弛操作中更新边的同时  记录路径!!!!!!!!!!!!!!
627             }
628     }
629     printf("s——>t  的最短路为 :");
630     printf("%d
",dis[t]);
631     printf("路径为 :");
632     //一下部分为路径的还原
633     queue<int >que;//申请一个队列
634     for(t;t!=-1;t=pre[t])//从t 一直寻找到s
635         que.push(t);//放入队列
636     printf("%d",que.front());//输出第一个
637     que.pop();//删除
638     while(!que.empty()){//队列不为空
639         printf("——>%d",que.front());//输出
640         que.pop();//删除
641     }
642 }
643 
644 int main()
645 {
646     int i, j, u, v, w, m;
647 
648     while(scanf("%d %d",&n,&m)==2){
649         for(i=0;i<n;i++)
650             for(j=0;j<n;j++)
651                 G[i][j] = i==j?0:INF;
652         while(m--){
653             scanf("%d %d %d",&u,&v,&w);
654             if(G[u][v]>w)
655                 G[u][v] = G[v][u] = w;
656         }
657         scanf("%d %d",&s,&t);
658         Dijkstra();
659     }
660     return 0;
661 }
662 */
原文地址:https://www.cnblogs.com/yijiull/p/6615820.html