转载链接:http://blog.csdn.net/niushuai666/article/details/6791765

Dijkstra算法是处理单源最短路径的有效算法,但它局限于边的权值非负的情况,若图中出现权值为负的边,Dijkstra算法就会失效,求出的最短路径就可能是错的。

这时候,就需要使用其他的算法来求解最短路径,Bellman-Ford算法就是其中最常用的一个。该算法由美国数学家理查德•贝尔曼(Richard Bellman, 动态规划的提出者)和小莱斯特•福特(Lester Ford)发明。

适用条件&范围:

单源最短路径(从源点s到其它所有顶点v);

有向图&无向图(无向图可以看作(u,v),(v,u)同属于边集E的有向图);

边权可正可负(如有负权回路输出错误提示);

差分约束系统;

Bellman-Ford算法的流程如下:
给定图G(V, E)(其中V、E分别为图G的顶点集与边集),源点s,数组Distant[i]记录从源点s到顶点i的路径长度,初始化数组Distant[n]为, Distant[s]为0;

以下操作循环执行至多n-1次,n为顶点数:
对于每一条边e(u, v),如果Distant[u] + w(u, v) < Distant[v],则另Distant[v] = Distant[u]+w(u, v)。w(u, v)为边e(u,v)的权值;
若上述操作没有对Distant进行更新,说明最短路径已经查找完毕,或者部分点不可达,跳出循环。否则执行下次循环;

为了检测图中是否存在负环路,即权值之和小于0的环路。对于每一条边e(u, v),如果存在Distant[u] + w(u, v) < Distant[v]的边,则图中存在负环路,即是说改图无法求出单源最短路径。否则数组Distant[n]中记录的就是源点s到各顶点的最短路径长度。

可知,Bellman-Ford算法寻找单源最短路径的时间复杂度为O(V*E).

Bellman-Ford算法可以大致分为三个部分
第一,初始化所有点。每一个点保存一个值,表示从原点到达这个点的距离,将原点的值设为0,其它的点的值设为无穷大(表示不可达)。
第二,进行循环,循环下标为从1到n-1(n等于图中点的个数)。在循环内部,遍历所有的边,进行松弛计算。
第三,遍历途中所有的边(edge(u,v)),判断是否存在这样情况:
d(v) > d (u) + w(u,v)
则返回false,表示途中存在从源点可达的权为负的回路。
 
之所以需要第三部分的原因,是因为,如果存在从源点可达的权为负的回路。则 应为无法收敛而导致不能求出最短路径。

测试代码如下:(下面为有向图的Bellman-Ford算法。。。。。)

  1. #include<iostream>
  2. #include<cstdio>
  3. using namespace std;
  4. #define MAX 0x3f3f3f3f
  5. #define N 1010
  6. int nodenum, edgenum, original; //点,边,起点
  7. typedef struct Edge //边
  8. {
  9. int u, v;
  10. int cost;
  11. }Edge;
  12. Edge edge[N];
  13. int dis[N], pre[N];
  14. bool Bellman_Ford()
  15. {
  16. for(int i = 1; i <= nodenum; ++i) //初始化
  17. dis[i] = (i == original ? 0 : MAX);
  18. for(int i = 1; i <= nodenum - 1; ++i)
  19. for(int j = 1; j <= edgenum; ++j)
  20. if(dis[edge[j].v] > dis[edge[j].u] + edge[j].cost) //松弛(顺序一定不能反~)
  21. {
  22. dis[edge[j].v] = dis[edge[j].u] + edge[j].cost;
  23. pre[edge[j].v] = edge[j].u;
  24. }
  25. bool flag = 1; //判断是否含有负权回路
  26. for(int i = 1; i <= edgenum; ++i)
  27. if(dis[edge[i].v] > dis[edge[i].u] + edge[i].cost)
  28. {
  29. flag = 0;
  30. break;
  31. }
  32. return flag;
  33. }
  34. void print_path(int root) //打印最短路的路径(反向)
  35. {
  36. while(root != pre[root]) //前驱
  37. {
  38. printf("%d-->", root);
  39. root = pre[root];
  40. }
  41. if(root == pre[root])
  42. printf("%d\n", root);
  43. }
  44. int main()
  45. {
  46. scanf("%d%d%d", &nodenum, &edgenum, &original);
  47. pre[original] = original;
  48. for(int i = 1; i <= edgenum; ++i)
  49. {
  50. scanf("%d%d%d", &edge[i].u, &edge[i].v, &edge[i].cost);
  51. }
  52. if(Bellman_Ford())
  53. for(int i = 1; i <= nodenum; ++i) //每个点最短路
  54. {
  55. printf("%d\n", dis[i]);
  56. printf("Path:");
  57. print_path(i);
  58. }
  59. else
  60. printf("have negative circle\n");
  61. return 0;
  62. }

Bellman-Ford模板的更多相关文章

  1. ACM/ICPC 之 最短路径-Bellman Ford范例(POJ1556-POJ2240)

    两道Bellman Ford解最短路的范例,Bellman Ford只是一种最短路的方法,两道都可以用dijkstra, SPFA做. Bellman Ford解法是将每条边遍历一次,遍历一次所有边可 ...

  2. poj1860 bellman—ford队列优化 Currency Exchange

    Currency Exchange Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 22123   Accepted: 799 ...

  3. uva 558 - Wormholes(Bellman Ford判断负环)

    题目链接:558 - Wormholes 题目大意:给出n和m,表示有n个点,然后给出m条边,然后判断给出的有向图中是否存在负环. 解题思路:利用Bellman Ford算法,若进行第n次松弛时,还能 ...

  4. Bellman—Ford算法思想

    ---恢复内容开始--- Bellman—Ford算法能在更普遍的情况下(存在负权边)解决单源点最短路径问题.对于给定的带权(有向或无向)图G=(V,E),其源点为s,加权函数w是边集E的映射.对图G ...

  5. Bellman - Ford 算法解决最短路径问题

    Bellman - Ford 算法: 一:基本算法 对于单源最短路径问题,上一篇文章中介绍了 Dijkstra 算法,但是由于 Dijkstra 算法局限于解决非负权的最短路径问题,对于带负权的图就力 ...

  6. bellman ford优先队列优化简介模板

    #include<iostream>#include<cstdio>#include<utility>#include<queue>#include&l ...

  7. Dijkstra算法与Bellman - Ford算法示例(源自网上大牛的博客)【图论】

    题意:题目大意:有N个点,给出从a点到b点的距离,当然a和b是互相可以抵达的,问从1到n的最短距离 poj2387 Description Bessie is out in the field and ...

  8. POJ 2240 Arbitrage (Bellman Ford判正环)

    Arbitrage Time Limit: 1000MS   Memory Limit: 65536K Total Submissions:27167   Accepted: 11440 Descri ...

  9. poj1860 兑换货币(bellman ford判断正环)

    传送门:点击打开链接 题目大意:一个城市有n种货币,m个货币交换点,你有v的钱,每个交换点只能交换两种货币,(A换B或者B换A),每一次交换都有独特的汇率和手续费,问你存不存在一种换法使原来的钱更多. ...

  10. ACM/ICPC 之 Bellman Ford练习题(ZOJ1791(POJ1613))

    这道题稍复杂一些,需要掌握字符串输入的处理+限制了可以行走的时间. ZOJ1791(POJ1613)-Cave Raider //限制行走时间的最短路 //POJ1613-ZOJ1791 //Time ...

随机推荐

  1. 20145301 赵嘉鑫 《网络对抗》Exp5 MSF基础应用

    20145301 赵嘉鑫 <网络对抗>Exp5 MSF基础应用 一 实验链接 渗透实验一:MS08_067渗透实验 渗透实验二:MS14_064渗透实验  (首用) 渗透实验三:Adobe ...

  2. WideCharToMultiByte和MultiByteToWideChar函数的用法(转载)

    出处:http://www.cnblogs.com/gakusei/articles/1585211.html 为了支持Unicode编码,需要多字节与宽字节之间的相互转换.这两个系统函数在使用时需要 ...

  3. jsp拾遗

    JSP九大内置对象,七大动作,三大指令 https://blog.csdn.net/qq_34337272/article/details/64310849 JSP页面的静态包含和动态包含 https ...

  4. 基础dp 记录

    51nod 1134 最长递增子序列 #include<iostream> #include<cstdio> #include<cstring> #include& ...

  5. hdu 6180 Schedule

    Schedule Problem Description There are N schedules, the i-th schedule has start time si and end time ...

  6. 51NOD 1081 子段求和

    1081 子段求和   给出一个长度为N的数组,进行Q次查询,查询从第i个元素开始长度为l的子段所有元素之和.   例如,1 3 7 9 -1,查询第2个元素开始长度为3的子段和,1 {3 7 9} ...

  7. js精度问题

    JavaScript数字精度丢失问题总结 现象 原因 计算机的二进制实现和位数限制有些数无法有限表示.就像一些无理数不能有限表示,如 圆周率 3.1415926...,1.3333... 等.JS 遵 ...

  8. codeforces 251 div2 C. Devu and Partitioning of the Array 模拟

    C. Devu and Partitioning of the Array time limit per test 1 second memory limit per test 256 megabyt ...

  9. 在采用vue-cli Post Get

    需要依赖插件 vue-resource npm install vue-resource --save https://cn.vuejs.org/v2/cookbook/using-axios-to- ...

  10. Python 以指定宽度格式化输出

    当对一组数据输出的时候,我们有时需要输出以指定宽度,来使数据更清晰.这时我们可以用format来进行约束 mat = "{:20}\t{:28}\t{:32}" print(mat ...