Dijkstra vs. Floyd-Warshall:在所有节点对上寻找最优路径
Posted
技术标签:
【中文标题】Dijkstra vs. Floyd-Warshall:在所有节点对上寻找最优路径【英文标题】:Dijkstra vs. Floyd-Warshall: Finding optimal route on all node pairs 【发布时间】:2011-05-11 21:03:26 【问题描述】:我正在阅读 Dijkstra 算法和 Floyd-Warshall 算法。我知道 Dijkstra 找到了从一个节点到所有其他节点的最佳路线,而 Floyd-Warshall 找到了所有节点配对的最佳路线。
我的问题是,如果我在每个节点上运行 Dijkstra 的算法以找到所有配对之间的最佳路线,它会比 Floyd 的算法更有效吗?
Dijkstra 的运行时间为 O(E + VlogV),而 Floyd 的运行时间为 O(V3)。如果 Dijkstra 失败,在这种情况下它的运行时间是多少?谢谢!
【问题讨论】:
the best shortest path algoritm 的可能重复项 【参考方案1】:正如其他人指出的那样,Floyd-Warshall 运行时间为 O(n3) 并运行 Dijkstra 从每个节点到另一个节点的搜索,假设您使用斐波那契堆来支持你的 Dijkstra 的实现需要 O(mn + n2 log n)。但是,您不能始终在任意图上安全地运行 Dijkstra 算法,因为 Dijkstra 算法不适用于负边权重。
有一个真正了不起的算法,称为 Johnson's algorithm,它是对从每个节点运行 Dijkstra 算法的轻微修改,即使图形包含负边(只要有不是任何负循环)。该算法首先在图上运行Bellman-Ford 以将其转换为没有负边的图,然后从每个顶点开始使用 Dijkstra 算法。因为 Bellman-Ford 运行时间为 O(mn),所以整体渐近运行时间仍然是 O(mn + n2 log n),所以如果 m = o(n2 )(请注意,这是 n 的 little-o),这种方法比使用 Floyd-Warshall 渐近更快。
这里的一个问题是,这假设您拥有由斐波那契堆支持的 Dijkstra 算法。如果您没有可用的斐波那契堆并且不愿意投入 72 小时来构建、调试和测试一个堆,那么您仍然可以为 Dijkstra 算法使用二进制堆;它只是将运行时间增加到 O(m log n),所以这个版本的 Johnson 算法在 O(mn log n) 中运行。这不再总是比 Floyd-Warshall 渐进快,因为如果 m = Ω(n2) 那么 Floyd-Warshall 运行时间为 O(n3) 而 Johnson 的算法运行在 O(n3 log n) 中。但是,对于 m = o(n2 / log n) 的稀疏图,Johnson 算法的这种实现仍然渐近优于 Floyd-Warshall
简而言之:
对于 Fibonacci 堆,Johnson 的算法总是渐近地至少与 Floyd-Warshall 一样好,尽管它更难编码。 对于二叉堆,Johnson 算法通常在渐近上至少与 Floyd-Warshall 一样好,但在处理大型密集图时不是一个好的选择。希望这会有所帮助!
【讨论】:
+ 用于提及约翰逊的算法 9 年半后......很好的答案。这几天我一直在寻找这个。谢谢@templatetypedef【参考方案2】:在所有节点上运行 Dijkstra 的复杂度为 O(EV + V2logV)。这个复杂度低于 O(V3) 当且仅当 E 2。
【讨论】:
这是真的。但是请注意,Floyd-Warshall 在内循环中执行的操作很少,因此在实践中,Floyd-Warshall 可能会比 Dijkstra 运行得更快,因为所有对最短路径。 请注意,E 【参考方案3】:这取决于。为所有节点运行 Dijkstra 会给你O(VE + V^2log V)
,而 Floyd 的则是O(V^3)
。如果E = O(V^2)
,那么两者在理论上是相同的,而弗洛伊德在实践中更快。如果你E = O(V)
,那么如果理论上和实践都更好,那么为所有节点运行 Dijkstra。
基本上,如果您希望拥有与节点数量一样多的边,则从所有节点运行 Dijkstra;如果您希望拥有几乎完整的图,则运行 Floyd。
【讨论】:
为什么是run Floyd if you expect to have almost complete graphs
?在这两种情况下运行 Dijkstra,速度有什么区别?为什么要让算法更难?
@Saeed - 因为在实践中,弗洛伊德应该更快(虽然我还没有测试过),因为V^2log V
术语。而且 Floyd 比最佳 Dijkstra 更容易实现,所以如果你只想使用一个,你不妨使用 Floyd。
@IVlad 我没有关注这个。 dijkstra 如果使用无序数组而不是堆天真地实现,将在 o(v^2) 时间内执行(每个节点最多有 v 个邻居)。对每个节点执行一次,导致 o(n^3) 时间。 Floyd 的真正优势似乎是它处理负边缘的能力(在其他 cmets 中表示)【参考方案4】:
对于所有对最短路径,几乎没有 Floyd-Warshall 比 Dijkstra 更快(通常!!)
【讨论】:
以上是关于Dijkstra vs. Floyd-Warshall:在所有节点对上寻找最优路径的主要内容,如果未能解决你的问题,请参考以下文章