【啊哈!算法】算法6:只有五行的Floyd最短路算法
![]() 暑假,小哼准备去一些城市旅游。有些城市之间有公路,有些城市之间则没有,如下图。为了节省经费以及方便计划旅程,小哼希望在出发之前知道任意两个城市之前的最短路程。
![]() 上图中有4个城市8条公路,公路上的数字表示这条公路的长短。请注意这些公路是单向的。我们现在需要求任意两个城市之间的最短路程,也就是求任意两个点之间的最短路径。这个问题这也被称为“多源最短路径”问题。
现在需要一个数据结构来存储图的信息,我们仍然可以用一个4*4的矩阵(二维数组e)来存储。比如1号城市到2号城市的路程为2,则设e[1][2]的值为2。2号城市无法到达4号城市,则设置e[2][4]的值为∞。另外此处约定一个城市自己是到自己的也是0,例如e[1][1]为0,具体如下。
<ignore_js_op>
现在回到问题:如何求任意两点之间最短路径呢?通过之前的学习我们知道通过深度或广度优先搜索可以求出两点之间的最短路径。所以进行n2遍深度或广度优先搜索,即对每两个点都进行一次深度或广度优先搜索,便可以求得任意两点之间的最短路径。可是还有没有别的方法呢?
我们来想一想,根据我们以往的经验,如果要让任意两点(例如从顶点a点到顶点b)之间的路程变短,只能引入第三个点(顶点k),并通过这个顶点k中转即a->k->b,才可能缩短原来从顶点a点到顶点b的路程。那么这个中转的顶点k是1~n中的哪个点呢?甚至有时候不只通过一个点,而是经过两个点或者更多点中转会更短,即a->k1->k2b->或者a->k1->k2…->k->i…->b。比如上图中从4号城市到3号城市(4->3)的路程e[4][3]原本是12。如果只通过1号城市中转(4->1->3),路程将缩短为11(e[4][1]+e[1][3]=5+6=11)。其实1号城市到3号城市也可以通过2号城市中转,使得1号到3号城市的路程缩短为5(e[1][2]+e[2][3]=2+3=5)。所以如果同时经过1号和2号两个城市中转的话,从4号城市到3号城市的路程会进一步缩短为10。通过这个的例子,我们发现每个顶点都有可能使得另外两个顶点之间的路程变短。好,下面我们将这个问题一般化。
当任意两点之间不允许经过第三个点时,这些城市之间最短路程就是初始路程,如下。
<ignore_js_op>
假如现在只允许经过1号顶点,求任意两点之间的最短路程,应该如何求呢?只需判断e[ i ][1]+e[1][j]是否比e[ i ][j]要小即可。e[ i ][j]表示的是从i号顶点到j号顶点之间的路程。e[ i ][1]+e[1][j]表示的是从i号顶点先到1号顶点,再从1号顶点到j号顶点的路程之和。其中i是1~n循环,j也是1~n循环,代码实现如下。
复制代码 在只允许经过1号顶点的情况下,任意两点之间的最短路程更新为:
![]() 通过上图我们发现:在只通过1号顶点中转的情况下,3号顶点到2号顶点(e[3][2])、4号顶点到2号顶点(e[4][2])以及4号顶点到3号顶点(e[4][3])的路程都变短了。
接下来继续求在只允许经过1和2号两个顶点的情况下任意两点之间的最短路程。如何做呢?我们需要在只允许经过1号顶点时任意两点的最短路程的结果下,再判断如果经过2号顶点是否可以使得i号顶点到j号顶点之间的路程变得更短。即判断e[ i ][2]+e[2][j]是否比e[ i ][j]要小,代码实现为如下。
复制代码 在只允许经过1和2号顶点的情况下,任意两点之间的最短路程更新为:
![]() 通过上图得知,在相比只允许通过1号顶点进行中转的情况下,这里允许通过1和2号顶点进行中转,使得e[1][3]和e[4][3]的路程变得更短了。
同理,继续在只允许经过1、2和3号顶点进行中转的情况下,求任意两点之间的最短路程。任意两点之间的最短路程更新为:
![]() 最后允许通过所有顶点作为中转,任意两点之间最终的最短路程为:
![]() 整个算法过程虽然说起来很麻烦,但是代码实现却非常简单,核心代码只有五行:
复制代码 这段代码的基本思想就是:最开始只允许经过1号顶点进行中转,接下来只允许经过1和2号顶点进行中转……允许经过1~n号所有顶点进行中转,求任意两点之间的最短路程。用一句话概括就是:从i号顶点到j号顶点只经过前k号点的最短路程。其实这是一种“动态规划”的思想,关于这个思想我们将在《啊哈!算法2——伟大思维闪耀时》在做详细的讨论。下面给出这个算法的完整代码:
复制代码 有一点需要注意的是:如何表示正无穷。我们通常将正无穷定义为99999999,因为这样即使两个正无穷相加,其和仍然不超过int类型的范围(C语言int类型可以存储的最大正整数是2147483647)。在实际应用中最好估计一下最短路径的上限,只需要设置比它大一点既可以。例如有100条边,每条边不超过100的话,只需将正无穷设置为10001即可。如果你认为正无穷和其它值相加得到一个大于正无穷的数是不被允许的话,我们只需在比较的时候加两个判断条件就可以了,请注意下面代码中带有下划线的语句。
复制代码 上面代码的输入数据样式为:
复制代码 第一行两个数为n和m,n表示顶点个数,m表示边的条数。
接下来m行,每一行有三个数t1、t2 和t3,表示顶点t1到顶点t2的路程是t3。
得到最终结果如下:
![]() 通过这种方法我们可以求出任意两个点之间最短路径。它的时间复杂度是O(N3)。令人很震撼的是它竟然只有五行代码,实现起来非常容易。正是因为它实现起来非常容易,如果时间复杂度要求不高,使用Floyd-Warshall来求指定两点之间的最短路或者指定一个点到其余各个顶点的最短路径也是可行的。当然也有更快的算法,请看下一节:Dijkstra算法。
另外需要注意的是:Floyd-Warshall算法不能解决带有“负权回路”(或者叫“负权环”)的图,因为带有“负权回路”的图没有最短路。例如下面这个图就不存在1号顶点到3号顶点的最短路径。因为1->2->3->1->2->3->…->1->2->3这样路径中,每绕一次1->-2>3这样的环,最短路就会减少1,永远找不到最短路。其实如果一个图中带有“负权回路”那么这个图则没有最短路。
<ignore_js_op>
此算法由Robert W. Floyd(罗伯特·弗洛伊德)于1962年发表在“Communications of the ACM”上。同年Stephen Warshall(史蒂芬·沃舍尔)也独立发表了这个算法。Robert W.Floyd这个牛人是朵奇葩,他原本在芝加哥大学读的文学,但是因为当时美国经济不太景气,找工作比较困难,无奈之下到西屋电气公司当了一名计算机操作员,在IBM650机房值夜班,并由此开始了他的计算机生涯。此外他还和J.W.J. Williams(威廉姆斯)于1964年共同发明了著名的堆排序算法HEAPSORT。堆排序算法我们将在第七章学习。Robert W.Floyd在1987年获得了图灵奖。
码字不容易啊,转载麻烦注明出处
【一周一算法】算法6:只有五行的Floyd最短路算法 http://bbs.ahalei.com/thread-4554-1-1.html (出处: 啊哈磊_编程从这里起步) |
【啊哈!算法】算法6:只有五行的Floyd最短路算法的更多相关文章
- 【坐在马桶上看算法】算法6:只有五行的Floyd最短路算法
暑假,小哼准备去一些城市旅游.有些城市之间有公路,有些城市之间则没有,如下图.为了节省经费以及方便计划旅程,小哼希望在出发之前知道任意两个城市之前的最短路程. 上图中有 ...
- 只有五行的Floyd最短路算法
暑假,小哼准备去一些城市旅游.有些城市之间有公路,有些城市之间则没有,如下图.为了节省经费以及方便计划旅程,小哼希望在出发之前知道任意两个城市之前的最短路程. 上图中有 ...
- 仅仅有五行的Floyd最短路算法
暑假,小哼准备去一些城市旅游.有些城市之间有公路,有些城市之间则没有,例如以下图.为了节省经费以及方便计划旅程,小哼希望在出发之前知道随意两个城市之前的最短路程. 上图中有4个城市8条公路,公路上的数 ...
- [转]坐在马桶上看算法:只有五行的Floyd最短路算法
此算法由Robert W. Floyd(罗伯特·弗洛伊德)于1962年发表在“Communications of the ACM”上.同年Stephen Warshall(史蒂芬·沃舍尔)也独立发表了 ...
- Floyd最短路算法
Floyd最短路算法 ----转自啊哈磊[坐在马桶上看算法]算法6:只有五行的Floyd最短路算法 暑假,小哼准备去一些城市旅游.有些城市之间有公路,有些城市之间则没有,如下图.为了节省经费以及方便计 ...
- 算法专题 | 10行代码实现的最短路算法——Bellman-ford与SPFA
今天是算法数据结构专题的第33篇文章,我们一起来聊聊最短路问题. 最短路问题也属于图论算法之一,解决的是在一张有向图当中点与点之间的最短距离问题.最短路算法有很多,比较常用的有bellman-ford ...
- Dijkstra 最短路算法(只能计算出一条最短路径,所有路径用dfs)
上周我们介绍了神奇的只有五行的 Floyd 最短路算法,它可以方便的求得任意两点的最短路径,这称为"多源最短路".本周来来介绍指定一个点(源点)到其余各个顶点的最短路径,也叫做&q ...
- Dijkstra最短路算法
Dijkstra最短路算法 --转自啊哈磊[坐在马桶上看算法]算法7:Dijkstra最短路算法 上节我们介绍了神奇的只有五行的Floyd最短路算法,它可以方便的求得任意两点的最短路径,这称为“多源最 ...
- 【啊哈!算法】算法7:Dijkstra最短路算法
上周我们介绍了神奇的只有五行的Floyd最短路算法,它可以方便的求得任意两点的最短路径,这称为“多源最短路”.本周来来介绍指定一个点(源点)到其余各个顶点的最短路径,也叫做“单源最短路径”.例如求下图 ...
随机推荐
- Ansible 的委托 并发和任务超时
异步和轮询 Ansible 有时候要执行等待时间很长的操作, 这个操作可能要持续很长时间, 设置超过ssh的timeout. 这时候你可以在step中指定async 和 poll 来实现异步操作 a ...
- 纯计算监控(Pure computed observables)
纯计算监控,在knockout 3.2.0里才有,提供了对性能和内存更好的管理.这是因为纯计算监控不包含对他的依赖的订阅.特点有: 防止内存泄漏 降低计算开销:值不再是observed,是一个不会重新 ...
- UIScrollView 加载多个view view还可以交换顺序(2)
在上的代码中 UIview都在一个页面 要是每一个view对应一个页面 操作每一个view代码都在viewcontroller里面就会很乱,那么我们就将view重新做一下 创建想要的页面继承与view ...
- [转载]The Island Castaway mac版解锁
http://blog.sina.com.cn/s/blog_506b3ac90101ke0e.html 1.首先,去安装一个The Island - Castaway™ mac free版,然后打开 ...
- 汇总jQuery的61种选择器及示例
汇总jQuery的61种选择器及示例 恋痿喃 ㄍń稀广 因罘乐睽 ú燔蒇 骤幄觳 ч豹 齑骝氮铷 宅廓Ω孓 锏遒 荛猩ㄜ彬 芡钷ж ┊贩错鹌 掩饰着可还是几步就窜到了门口看着这个让她 ...
- log4j2日志
log4j2.xmllog4j-api-2.5.jarlog4j-core-2.5.jar <?xml version="1.0" encoding="UTF-8& ...
- 给windows共享 目录付于权限
1.点右监 共享给 某用户 2.点属性 -> 安全 加入 特定用户 3.域用户的管理 (选择控制面板/用户管理) 第一个用户是本地账户 第2/3个是域用户
- netsh命令之ip设置
批处理.VBS实现自动设置IP.默认网关.DNS.WINS.IE代理的代码,需要的朋友可以参考下 因为公司有同事负责大连.沈阳两个城市,经常在两地来回走动,到每个城市后,都要自己手动更改相应的网络配置 ...
- HDU - 2255 奔小康赚大钱(最大带权匹配)
Problem Description 传说在遥远的地方有一个非常富裕的村落,有一天,村长决定进行制度改革:重新分配房子.这可是一件大事,关系到人民的住房问题啊.村里共有n间房间,刚好有n家老百姓, ...
- Oracle技术整理(转载)






