Floyd-Warshall算法
Floyd-Warshall算法是一种最短路径算法图.就像bellman算法或者是迪杰斯特拉算法,它计算图中的最短路径。然而,Bellman-Ford和Dijkstra都是单源、最短路径算法。这意味着它们只计算来自单个源的最短路径。另一方面,Floyd-Warshall计算输入图中每对顶点之间的最短距离。
假设你有5个朋友:比利、珍娜、卡西、阿丽莎和哈利。你知道有几条路连接着他们的一些房子,你也知道这些路的长度。但是Floyd-Warshall可以根据你所知道的信息给出最优路线。例如,看看下面的图表,它显示了从一个朋友到另一个朋友的路径和相应的距离。
Floyd-Warshall会告诉我们两者的最佳距离每一个一对朋友。它会清楚地告诉你,从Alyssa家到Harry家的最快路径是权重为1的连接边。但是,它也会告诉你,从比利家到珍娜家的最快路线是先经过凯西家,然后是艾莉莎家,然后是哈利家,最后到达珍娜家。这就是弗洛伊德-沃沙尔的力量;不管你现在在哪个房子,它都会告诉你去其他房子的最快路线。
Floyd-Warshall算法就是一个例子动态规划.它将问题分解成更小的子问题,然后结合这些子问题的答案来解决大的初始问题。思路是这样的:要么从A到C的最快路径是目前为止从A到C的最快路径,要么是从A到B的最快路径加上从B到C的最快路径。
Floyd-Warshall在网络中非常有用,类似于最短路径问题的解决方案。然而,由于它可以计算出所有相关节点之间的最短路径,因此在管理路线上的多个站点时更有效。事实上,Floyd-Warshall的一次运行就可以提供你需要知道的关于静态网络的所有信息,从而优化大多数类型的路径。它在计算矩阵逆时也很有用。
内容
概述
Floyd-Warshall的核心是这个功能:
这个函数返回从的最短路径 来 使用从1到的顶点 在图中。顶点是单独编号的 .
有一个基本情况和一个递归的情况。基本情况是最短路径就是连接的边的权值 和
递归的情况将利用动态规划这个问题的本质。这个函数有两种可能的答案。两者之间的最短路径 和 是已知最短路径,还是从这里出发的已知最短路径 到某个顶点(我们叫它 )加上从 来
基本上,这个函数设置问的是:"顶点是 最短路径的中间点(除了第一个或最后一个顶点之外的任何顶点)
如果 不是一个中间顶点,那么最短路径从哪里来 来 使用中的顶点 也是用顶点的最短路径吗
如果 是一个中间顶点,那么路径可以被分解成两条路径,每条路径使用的顶点在 中的所有顶点创建一个路径 这是因为顶点 是中间点。如下图所示。
算法
Floyd-Warshall算法可以用以下伪代码描述:
12 3 4 5 6 7 8 9 10 11 12 13 |
|
复杂性
示例Python实现
Floyd-Warshall的以下实现是用Python编写的。
在这个实现中,无穷大由一个非常大的整数表示。
12 34 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 44 45 46 47 48 49 50 51 52 |
|
的边缘
第一行的类是一个简单的对象,它保存有关边缘的信息,如端点和权重。在这个实现中,顶点只是一个简单的整数。的图
类使用字典(在第9行初始化)来表示图。这个字典中的键是顶点数,值是边的列表。
的floydwarshall ()
函数在第33行创建一个矩阵米
.它用每个顶点的最短路径信息填充这个矩阵。例如,从顶点0到顶点2的最短路径距离可以在M [0] [2]
.
道路重建
一般来说,Floyd-Warshall,在最基本的情况下,只提供了结果矩阵中顶点之间的距离。然而,一个简单的改变也可以让算法重建最短路径。有许多不同的方法可以做到这一点,所有这些方法都有内存开销。速度不是路径重建的一个因素,因为重建路径所花费的任何时间与基本算法本身相比都显得微不足道。
最常见的方法是计算一个前导矩阵的序列。在路径计算过程中,即使是矩阵
可以计算。 定义为顶点的前导 从顶点出发的最短路径 集合中所有的中间点 .因此,对于主循环的每次迭代,都会创建一个新的前导矩阵。
该前代矩阵的递归公式为:
如果
或
如果
和