Flyer
bellman ford 算法
- 数组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 = (V, E) 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 δ(s, v). 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 i ← 1 to |V[G]| - 1 3 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 FALSE 8 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代码:
补充:
考虑:为什么要循环V-1次?
答:因为最短路径肯定是个简单路径,不可能包含回路的,
如果包含回路,且回路的权值和为正的,那么去掉这个回路,可以得到更短的路径
如果回路的权值是负的,那么肯定没有解了
图有n个点,又不能有回路
所以最短路径最多n-1边
又因为每次循环,至少relax一边
所以最多n-1次就行了
- 顶
- 3
- 踩
- 0
参考知识库
-
算法与数据结构知识库
- 猜你在找
核心技术类目
- 文章搜索
- 文章分类
- 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
结构之法 算法之道
暂无评论