最短路径算法之Floyd算法
Posted Python那些事
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了最短路径算法之Floyd算法相关的知识,希望对你有一定的参考价值。
Floyd算法简称F算法由Robert W. Floyd(罗伯特·弗洛伊德)于1962年发表提出的,解决了图中任意节点间的最短路径问题。
以下图中的城市的道路为例:
上图中有4个城市8条公路,公路上的数字表示这条公路的长短。请注意这些公路是单向的。我们现在需要求任意两个城市之间的最短路程,也就是求任意两个点之间的最短路径。这个问题这也被称为“多源最短路径”问题。
现在需要一个数据结构来存储图的信息,我们仍然可以用一个4*4的矩阵(二维数组G)来存储。比如1号城市到2号城市的路程为2,则设G[1][2]的值为2。2号城市无法到达4号城市,则设置G[2][4]的值为∞。另外此处约定一个城市自己是到自己的也是0,例如G[1][1]为0,具体如下。
现在回到问题:如何求任意两点之间最短路径呢?通过之前的学习我们知道通过D算法可以求一点到其它节点的最短路径。所以进行n次D算法,便可以求得任意两点之间的最短路径。可是还有没有别的方法呢?
我们来想一想,根据我们以往的经验,如果要让任意两点(例如从顶点a点到顶点b)之间的路程变短,只能引入第三个点(顶点k),并通过这个顶点k中转即a->k->b,才可能缩短原来从顶点a点到顶点b的路程。那么这个中转的顶点k是1~n中的哪个点呢?甚至有时候不只通过一个点,而是经过两个点或者更多点中转会更短,即a->k1->k2->b或者a->k1->k2…->ki…->b。比如上图中从4号城市到3号城市(4->3)的路程G[4][3]原本是12。如果只通过1号城市中转(4->1->3),路程将缩短为11(G[4][1]+G[1][3]=5+6=11)。其实1号城市到3号城市也可以通过2号城市中转,使得1号到3号城市的路程缩短为5(G[1][2]+G[2][3]=2+3=5)。所以如果同时经过1号和2号两个城市中转的话,从4号城市到3号城市的路程会进一步缩短为10。通过这个的例子,我们发现每个顶点都有可能使得另外两个顶点之间的路程变短。
当任意两点之间不允许经过第三个点时,这些城市之间最短路程就是初始路程,如下:
如现在只允许经过1号顶点,求任意两点之间的最短路程,应该如何求呢?只需判断G[i][1]+G[1][j]是否比G[i][j]要小即可。G[i][j]表示的是从i号顶点到j号顶点之间的路程。G[i][1]+G[1][j]表示的是从i号顶点先到1号顶点,再从1号顶点到j号顶点的路程之和。其中i是1~n循环,j也是1~n循环。
通过上图我们发现:在只通过1号顶点中转的情况下,3号顶点到2号顶点(G[3][2])、4号顶点到2号顶点(G[4][2])以及4号顶点到3号顶点(G[4][3])的路程都变短了。
接下来继续求在只允许经过1和2号两个顶点的情况下任意两点之间的最短路程。如何做呢?我们需要在只允许经过1号顶点时任意两点的最短路程的结果下,再判断如果经过2号顶点是否可以使得i号顶点到j号顶点之间的路程变得更短。即判断G[i][2]+G[2][j]是否比G[i][j]要小。
在只允许经过1和2号顶点的情况下,任意两点之间的最短路程更新为:
通过上图得知,在相比只允许通过1号顶点进行中转的情况下,这里允许通过1和2号顶点进行中转,使得G[1][3]和G[4][3]的路程变得更短了。
同理,继续在只允许经过1、2和3号顶点进行中转的情况下,求任意两点之间的最短路程。任意两点之间的最短路程更新为:
最后允许通过所有顶点作为中转,任意两点之间最终的最短路程为:
算法代码实现如下:
import copy
maxDis = 1000000
def Floyd(G):
n = len(G)
path = copy.deepcopy(G)
for k in range(0, n):
for i in range(0, n):
for j in range(0, n):
path[i][j] = min(path[i][j], path[i][k] + path[k][j])
return path
if __name__ == '__main__':
G = [
[0, 2, 6, 4],
[maxDis, 0, 3, maxDis],
[7, maxDis, 0, 1],
[5, maxDis, 12, 0],
]
path = Floyd(G)
for i in range(0, len(G)):
print path[i]
今天,你学会了Floyd最短路径算法了吗?
以上是关于最短路径算法之Floyd算法的主要内容,如果未能解决你的问题,请参考以下文章