📜  约翰逊的全对最短路径算法

📅  最后修改于: 2022-05-13 01:57:54.551000             🧑  作者: Mango

约翰逊的全对最短路径算法

问题是在给定的加权有向图中找到每对顶点之间的最短路径,并且权重可能为负。我们已经针对这个问题讨论了 Floyd Warshall 算法。 Floyd Warshall 算法的时间复杂度为 Θ(V 3 )。使用约翰逊算法,我们可以在 O(V 2 log V + VE) 时间内找到所有对的最短路径。 Johnson 的算法使用 Dijkstra 和 Bellman-Ford 作为子程序。

如果我们对每个顶点应用 Dijkstra 的单源最短路径算法,将每个顶点视为源,我们可以在 O(V*VLogV) 时间内找到所有对最短路径。所以使用 Dijkstra 的单源最短路径似乎是比 Floyd Warshell 更好的选择,但 Dijkstra 算法的问题是,它不适用于负权边缘。
约翰逊算法的想法是重新加权所有边并使它们全部为正,然后对每个顶点应用 Dijkstra 算法。

如何将给定的图转换为具有所有非负权重边的图?
人们可能会想到一种简单的方法来找到最小权重边缘并将此权重添加到所有边缘。不幸的是,这不起作用,因为在不同的路径中可能有不同数量的边(参见这个例子)。如果从顶点 u 到 v 有多条路径,则所有路径必须增加相同的量,以便最短路径在变换后的图中保持最短。
约翰逊算法的思想是为每个顶点分配一个权重。让分配给顶点 u 的权重为 h[u]。我们使用顶点权重重新加权边缘。例如,对于权重为 w(u, v) 的边 (u, v),新的权重变为 w(u, v) + h[u] – h[v]。这种重新加权的好处是,任何两个顶点之间的所有路径集都增加了相同的数量,并且所有负权重都变为非负数。考虑两个顶点 s 和 t 之间的任何路径,每条路径的权重增加 h[s] – h[t],从 s 到 t 的路径上的所有顶点的 h[] 值相互抵消。

我们如何计算 h[] 值? Bellman-Ford 算法用于此目的。以下是完整的算法。一个新的顶点被添加到图中并连接到所有现有的顶点。从新顶点到所有现有顶点的最短距离值是 h[] 值。

算法:
1)设给定图为 G。向图中添加一个新顶点 s,将新顶点的边添加到 G 的所有顶点。令修改后的图为 G'。

2)以 s 为源在 G' 上运行 Bellman-Ford 算法。让 Bellman-Ford 计算的距离为 h[0], h[1], .. h[V-1]。如果我们发现负权重循环,则返回。请注意,负权重循环不能由新顶点 s 创建,因为 s 没有边。所有边都来自 s。

3)重新加权原始图的边缘。对于每条边 (u, v),将新权重分配为“原始权重 + h[u] – h[v]”。

4)删除添加的顶点s,对每个顶点运行Dijkstra算法。

转换如何确保非负权重边缘?
以下属性对于 h[] 值始终成立,因为它们是最短距离。

h[v] <= h[u] + w(u, v) 

该性质简单地说,从 s 到 v 的最短距离必须小于或等于从 s 到 u 的最短距离加上边的权重 (u, v)。新的权重是 w(u, v) + h[u] - h[v]。由于不等式“h[v] <= h[u] + w(u, v)”,新权重的值必须大于或等于零。例子:
让我们考虑下图。

约翰逊1

我们添加一个源 s 并将来自 s 的边添加到原始图的所有顶点。在下图中,s 为 4。

约翰逊2

我们使用 Bellman-Ford 算法计算从 4 到所有其他顶点的最短距离。 4到0、1、2、3的最短距离分别为0、-5、-1、0,即h[] = {0, -5, -1, 0}。一旦我们得到这些距离,我们删除源顶点 4 并使用以下公式重新加权边缘。 w(u, v) = w(u, v) + h[u] - h[v]。

约翰逊3

由于现在所有的权重都是正的,我们可以为每个作为源的顶点运行 Dijkstra 的最短路径算法。

时间复杂度:算法的主要步骤是 Bellman Ford 算法称为一次和 Dijkstra 称为 V 次。 Bellman Ford 的时间复杂度为 O(VE),Dijkstra 的时间复杂度为 O(VLogV)。所以整体时间复杂度是 O(V 2 log V + VE)。
当图完整时,Johnson 算法的时间复杂度与 Floyd Warshell 相同(对于完整图 E = O(V 2 )。但对于稀疏图,该算法的性能比 Floyd Warshell 好得多。

参考:
Clifford Stein、Thomas H. Cormen、Charles E. Leiserson、Ronald L. Rivest 的算法介绍第 3 版
http://www.youtube.com/watch?v=b6LOHvCzmkI
http://www.youtube.com/watch?v=TV2Z6nbo1ic
http://en.wikipedia.org/wiki/Johnson%27s_algorithm
http://www.youtube.com/watch?v=Sygq1e0xWnM