bellman ford 算法 判断是否存在负环

来源:互联网 发布:星型网络 编辑:程序博客网 时间:2024/05/22 09:02
微信小程序实战项目——点餐系统        程序员11月书讯,评论得书啦        Get IT技能知识库,50个领域一键直达
关闭
 

bellman ford 算法

 11148人阅读 评论(0) 收藏 举报
 分类:

[cpp] view plain copy
  1. <span style="font-family: Arial, Helvetica, sans-serif;"><span style="border-bottom-width:1px; border-bottom-style:dashed; border-bottom-color:rgb(201,201,201)"><a href="http://www.wutianqi.com/?p=1890" target="_blank" style="background-color:transparent; border-width:0px 0px 1px; border-bottom-style:dashed; border-bottom-color:rgb(201,201,201); margin:0px; padding:0px; vertical-align:baseline; color:rgb(0,102,204); text-decoration:none; outline:none">Dijkstra算法</a></span></span><a href="http://wutianqi-blog.b0.upaiyun.com/2011/01/2.png" style="font-family: Arial, Helvetica, sans-serif; background-color: transparent; border-width: 0px 0px 1px; border-bottom-style: dashed; border-bottom-color: rgb(201, 201, 201); margin: 0px; padding: 0px; vertical-align: baseline; color: rgb(0, 102, 204); text-decoration: none; outline: none;"></a><a href="http://wutianqi-blog.b0.upaiyun.com/2011/01/4.png" style="font-family: Arial, Helvetica, sans-serif; background-color: transparent; border-width: 0px 0px 1px; border-bottom-style: dashed; border-bottom-color: rgb(201, 201, 201); margin: 0px; padding: 0px; vertical-align: baseline; color: rgb(0, 102, 204); text-decoration: none; outline: none;"></a><a href="http://wutianqi-blog.b0.upaiyun.com/2011/01/bellman_ford.jpg" style="font-family: Arial, Helvetica, sans-serif; background-color: transparent; border-width: 0px 0px 1px; border-bottom-style: dashed; border-bottom-color: rgb(201, 201, 201); margin: 0px; padding: 0px; vertical-align: baseline; color: rgb(0, 102, 204); text-decoration: none; outline: none;"></a><span style="font-family: Arial, Helvetica, sans-serif;">是处理单源最短路径的有效算法,但它局限于边的权值非负的情况,若图中出现权值为负的边,Dijkstra算法就会失效,求出的最短路径就可能是错的。这时候,就需要使用其他的算法来求解最短路径,</span><a href="http://www.wutianqi.com/?p=1912" target="_blank" style="font-family: Arial, Helvetica, sans-serif; background-color: transparent; border-width: 0px 0px 1px; border-bottom-style: dashed; border-bottom-color: rgb(201, 201, 201); margin: 0px; padding: 0px; vertical-align: baseline; color: rgb(0, 102, 204); text-decoration: none; outline: none;">Bellman-Ford算法</a><span style="font-family: Arial, Helvetica, sans-serif;">就是其中最常用的一个。该算法由美国数学家理查德•贝尔曼(Richard Bellman, 动态规划的提出者)和小莱斯特•福特(Lester Ford)发明。Bellman-Ford算法的流程如下:</span>  
给定图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).

首先介绍一下松弛计算。如下图:


 

松弛计算之前,点B的值是8,但是点A的值加上边上的权重2,得到5,比点B的值(8)小,所以,点B的值减小为5。这个过程的意义是,找到了一条通向B点更短的路线,且该路线是先经过点A,然后通过权重为2的边,到达点B。
当然,如果出现一下情况


 

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

经过第一次遍历后,点B的值变为5,点C的值变为8,这时,注意权重为-10的边,这条边的存在,导致点A的值变为-2。(8+ -10=-2)
 
 

第二次遍历后,点B的值变为3,点C变为6,点A变为-4。正是因为有一条负边在回路中,导致每次遍历后,各个点的值不断变小。
 
在回过来看一下bellman-ford算法的第三部分,遍历所有边,检查是否存在d(v) > d (u) + w(u,v)。因为第二部分循环的次数是定长的,所以如果存在无法收敛的情况,则肯定能够在第三部分中检查出来。比如
 

此时,点A的值为-2,点B的值为5,边AB的权重为5,5 > -2 + 5. 检查出来这条边没有收敛。
 
所以,Bellman-Ford算法可以解决图中有权为负数的边的单源最短路径问。

个人感觉算法导论讲解很不错,把这一章贴出来和大家分享:

24.1 The Bellman-Ford algorithm

The Bellman-Ford algorithm solves the single-source shortest-paths problem in the general case in which edge weights may be negative. Given a weighted, directed graph G = (VE) with source s and weight function w : E → R, the Bellman-Ford algorithm returns a boolean value indicating whether or not there is a negative-weight cycle that is reachable from the source. If there is such a cycle, the algorithm indicates that no solution exists. If there is no such cycle, the algorithm produces the shortest paths and their weights.

The algorithm uses relaxation, progressively decreasing an estimate d[v] on the weight of a shortest path from the source s to each vertex v ∈ V until it achieves the actual shortest-path weight δ(sv). The algorithm returns TRUE if and only if the graph contains no negative-weight cycles that are reachable from the source.

BELLMAN-FORD(G, w, s)1  INITIALIZE-SINGLE-SOURCE(G, s)2  for i1 to |V[G]| - 13       do for each edge (u, v) ∈ E[G]4              do RELAX(u, v, w)5  for each edge (u, v) ∈ E[G]6       do if d[v] > d[u] + w(u, v)7             then return FALSE8  return TRUE

Figure 24.4 shows the execution of the Bellman-Ford algorithm on a graph with 5 vertices. After initializing the d and π values of all vertices in line 1, the algorithm makes |V| – 1 passes over the edges of the graph. Each pass is one iteration of the for loop of lines 2-4 and consists of relaxing each edge of the graph once. Figures 24.4(b)-(e) show the state of the algorithm after each of the four passes over the edges. After making |V|- 1 passes, lines 5-8 check for a negative-weight cycle and return the appropriate boolean value. (We’ll see a little later why this check works.)

(单击图片可以放大)

Figure 24.4: The execution of the Bellman-Ford algorithm. The source is vertex s. The d values are shown within the vertices, and shaded edges indicate predecessor values: if edge (u, v) is shaded, then π[v] = u. In this particular example, each pass relaxes the edges in the order (t, x), (t, y), (t, z), (x, t), (y, x), (y, z), (z, x), (z, s), (s, t), (s, y). (a) The situation just before the first pass over the edges. (b)-(e) The situation after each successive pass over the edges. The d and π values in part (e) are the final values. The Bellman-Ford algorithm returns TRUE in this example.

The Bellman-Ford algorithm runs in time O(V E), since the initialization in line 1 takes Θ(V) time, each of the |V| – 1 passes over the edges in lines 2-4 takes Θ(E) time, and the for loop of lines 5-7 takes O(E) time.

以下是Bellman-Ford代码:

[cpp] view plain copy
  1. #include <iostream>  
  2. using namespace std;  
  3. const int maxnum = 100;  
  4. const int maxint = 99999;  
  5.   
  6. // 边,  
  7. typedef struct Edge{  
  8.     int u, v;    // 起点,重点  
  9.     int weight;  // 边的权值  
  10. }Edge;  
  11.   
  12. Edge edge[maxnum];     // 保存边的值  
  13. int  dist[maxnum];     // 结点到源点最小距离  
  14.   
  15. int nodenum, edgenum, source;    // 结点数,边数,源点  
  16.   
  17. // 初始化图  
  18. void init()  
  19. {  
  20.     // 输入结点数,边数,源点  
  21.     cin >> nodenum >> edgenum >> source;  
  22.     for(int i=1; i<=nodenum; ++i)  
  23.         dist[i] = maxint;  
  24.     dist[source] = 0;  
  25.     for(int i=1; i<=edgenum; ++i)  
  26.     {  
  27.         cin >> edge[i].u >> edge[i].v >> edge[i].weight;  
  28.         if(edge[i].u == source)          //注意这里设置初始情况  
  29.             dist[edge[i].v] = edge[i].weight;  
  30.     }  
  31. }  
  32.   
  33. // 松弛计算  
  34. void relax(int u, int v, int weight)  
  35. {  
  36.     if(dist[v] > dist[u] + weight)  
  37.         dist[v] = dist[u] + weight;  
  38. }  
  39.   
  40. bool Bellman_Ford()  
  41. {  
  42.     for(int i=1; i<=nodenum-1; ++i)  
  43.         for(int j=1; j<=edgenum; ++j)  
  44.             relax(edge[j].u, edge[j].v, edge[j].weight);  
  45.     bool flag = 1;  
  46.     // 判断是否有负环路  
  47.     for(int i=1; i<=edgenum; ++i)  
  48.         if(dist[edge[i].v] > dist[edge[i].u] + edge[i].weight)  
  49.         {  
  50.             flag = 0;  
  51.             break;  
  52.         }  
  53.     return flag;  
  54. }  
  55. int main()  
  56. {  
  57.     //freopen("input3.txt", "r", stdin);  
  58.     init();  
  59.     if(Bellman_Ford())  
  60.         for(int i = 1 ;i <= nodenum; i++)  
  61.             cout << dist[i] << endl;  
  62.     return 0;  
  63. }  


补充:


考虑:为什么要循环V-1次?
答:因为最短路径肯定是个简单路径,不可能包含回路的,
如果包含回路,且回路的权值和为正的,那么去掉这个回路,可以得到更短的路径
如果回路的权值是负的,那么肯定没有解了

图有n个点,又不能有回路
所以最短路径最多n-1边

又因为每次循环,至少relax一边
所以最多n-1次就行了

3
0
 
 

我的同类文章

  • Uva 10891 sum 游戏 (及其变型) ;动态规划2013-05-31
  • 二分图匹配算法总结2013-05-25
  • 求最大权二分匹配的KM算法2013-05-25
  • ACM进阶指南2013-05-25
  • 匈牙利算法 求解 完美的牛栏2013-05-24
  • 欧拉回路2013-05-28
  • 二分图带权匹配 KM算法与费用流模型建立2013-05-25
  • 著名的北邮ACM推荐50题2013-05-25
  • HDOJ---2036 过山车[匈牙利算法]2013-05-24
  • hdu 1466计算直线的交点数2013-05-03
更多文章

参考知识库

img

算法与数据结构知识库

猜你在找
《C语言/C++学习指南》加密解密篇(安全相关算法)
C语言系列之 递归算法示例与 Windows 趣味小项目
C语言系列之 字符串相关算法
C语言系列之 字符串压缩算法与结构体初探
模板匹配的字符识别(OCR)算法原理
图最短路径Bellman-Ford算法
BellmanFord算法实现解决存在负边情况下单源最短路径问题
最短路模板Dijkstra & Dijkstra算法+堆优化 & bellman_ford & 单源最短路SPFA
最短路径算法Bellman-Ford贝尔曼
poj Wormholes 最短路 spfa Bellman-Ford 算法 邻接表实现
查看评论

  暂无评论

发表评论
  • 用 户 名:
  • hang__xiu2016acm
  • 评论内容:
  • 插入代码
      
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
核心技术类目
全部主题 Hadoop AWS 移动游戏 Java Android iOS Swift 智能硬件 Docker OpenStack VPN Spark ERP IE10Eclipse CRM JavaScript 数据库 Ubuntu NFC WAP jQuery BI HTML5 Spring Apache .NET API HTML SDK IISFedora XML LBS Unity Splashtop UML components Windows Mobile Rails QEMU KDE Cassandra CloudStack FTCcoremail OPhone CouchBase 云计算 iOS6 Rackspace Web App SpringSide Maemo Compuware 大数据 aptech PerlTornado Ruby Hibernate ThinkPHP HBase Pure Solr Angular Cloud Foundry Redis Scala Django Bootstrap
    个人资料
     
    Flyer_
     
    1
    • 访问:75445次
    • 积分:1071
    • 等级: 
    • 排名:千里之外
    • 原创:24篇
    • 转载:47篇
    • 译文:0篇
    • 评论:10条
    文章分类
  • unix环境高级编程(18)
  • unix网络编程(4)
  • tcp/ip(4)
  • unix/linux(10)
  • ACM(12)
  • 笔试(13)
  • 面试(8)
  • PAT(4)
  • 30天自制操作系统(1)
  • 前端(4)
  • HTML&CSS(3)
  • ML(7)
    文章存档
  • 2016年10月(1)
  • 2016年08月(1)
  • 2016年07月(6)
  • 2015年07月(3)
  • 2015年03月(1)
    展开
    阅读排行
  • bellman ford 算法(11142)
  • 网络爬虫c实现(9636)
  • 2014阿里巴巴9月14北京校园招聘笔试及参考答案(3983)
  • 两道操作系统题目---多道程序(3511)
  • TCP/IP网络编程之四书五经(2704)
  • 2012九月十月腾讯,网易游戏,百度最新校园招聘笔试题(2619)
  • Linux进程地址空间与虚拟内存(2337)
  • PAT 1010. 一元多项式求导 (25)(2186)
  • PAT 1009. 说反话 (20)(2011)
  • 腾讯后台开发面试题(1764)
    评论排行
  • 2014阿里巴巴9月14北京校园招聘笔试及参考答案(3)
  • 网络爬虫c实现(2)
  • 进程与线程的一个简单解释(2)
  • 两道操作系统题目---多道程序(1)
  • LINUX/UNIX 文件状态标志的 与或非 操作(1)
  • 编程之美_单链表面试题_结合3.4_3.6(1)
  • 2014找工作总结-机会往往留给有准备的人(1)
  • 著名的北邮ACM推荐50题(0)
  • ACM进阶指南(0)
  • 匈牙利算法 求解 完美的牛栏(0)
    推荐文章
    • * RxJava详解,由浅入深
    • * 倍升工作效率的小策略
    • * Android热修复框架AndFix原理解析及使用
    • * “区块链”究竟是什么鬼
    • * 架构设计:系统存储-MySQL主从方案业务连接透明化(中)
    最新评论
  • 两道操作系统题目---多道程序

    Daringoo: 第二题,腾讯给的标准答案是A。在csdn上有自动的测试,我看到了显示的答案。但是不知怎么得来的。

  • ssd8ex1

    Tiger_Humour: 楼主你好,请问18到25行代码里的;这一段代码是如何确定uri.indexOf('/',8)+1的。...

  • 网络爬虫c实现

    Echo_Wei1991: 正在写这个的大作业,谢谢啦~太赞

  • 进程与线程的一个简单解释

    qwe8642511: 很好,但是为什么那个锁上在了门外面。。。。。。出不来了~

  • 2014阿里巴巴9月14北京校园招聘笔试及参考答案

    weidahou227: @xiaor186:大哥你能好好算算在评论吗,字母有重复的

  • 2014阿里巴巴9月14北京校园招聘笔试及参考答案

    xiaor186: 哎,哥啊,看来这参考答案也真的是只能是参考下而已。第一个的答案用脚趾数都不可能是D吧,应该是A

  • 编程之美_单链表面试题_结合3.4_3.6

    岁月小龙: 没有实现代码啊

  • 网络爬虫c实现

    岁月小龙: xialai慢慢看

  • 进程与线程的一个简单解释

    岁月小龙: 这个图文并茂,真是太好了

  • 2014找工作总结-机会往往留给有准备的人

    Deebug: 谢谢博主的建议。+1

    链接
    Hackbuteer1
    结构之法 算法之道
0 0
原创粉丝点击