Johnson 全源负权最短路径算法详解

2025-02-17 10:16

Floyd-Warshall算法可以求解出图内任意两点的最短路径,适用于稠密图,但时间复杂度为 \(O(n³)\)Dijkstra算法求解单源最短路径的时间复杂度为 \(O(m + n log n)\),对每个节点都做一次,也可以达成全源最短路径,但是这个方法仅适用于非负权边图。

Johnson 算法被设计来解决此问题,其支持负权边(当然不能有负权环)。综合两个算法的优势,时间复杂度 \(O(nm + n² log n)\),在稀疏图中显著优于 Floyd-Warshall,结合了 Dijkstra 的高效性与 Bellman-Ford 的灵活性。

1 添加虚拟节点

在原始图 \(G\) 中添加一个虚拟节点 \(s\),并添加从 \(s\) 到所有原节点的边,权重为0。为后续计算势能函数做准备。

2 计算势能函数 \(h(v)\)

使用 Bellman-Ford / SPFA 算法 计算从 \(s\) 到所有原节点的最短路径,结果记为 \(h(v)\)。若检测到负权环,算法终止(此时原图无有效最短路径)。

3 调整边权为非负值

对原图中每条边 \((u, v)\),调整权重为:

\[w'(u, v) = w(u, v) + h(u) - h(v) \]

经过这样调整,调整后所有新的边权重 \(w'(u, v)\) 均为非负。且满足“原图的最短路同样是新图的最短路”

4 运行Dijkstra算法

对调整后的图,为每个节点 \(u\) 运行一次Dijkstra算法,得到最短路径 \(d'(u, v)\)

5 还原原始最短路径

原始图中 \(u\)\(v\) 的最短路径为:

\[d(u, v) = d'(u, v) - h(u) + h(v) \]

为什么是对的?

1 边权调整的非负性

\(h\) 是虚拟点到节点的距离,根据 Bellman-Ford 的最短路径性质,对任意边 \((u, v)\) 有:

\[h(v) \leq h(u) + w(u, v) \]

移项得:

\[w(u, v) + h(u) - h(v) \geq 0 \]

因此,调整后的权重 \(w'(u, v)\) 非负,Dijkstra算法可正确运行。

2 最短路径的等价性

设原图中一条路径 \(p = v₀ → v₁ → ... → vₖ\) 的权重和为:

\[W(p) = \sum_{i=0}^{k-1} w(v_i, v_{i+1}) \]

调整后的权重和为:

\[W'(p) = \sum_{i=0}^{k-1} [w(v_i, v_{i+1}) + h(v_i) - h(v_{i+1})] = W(p) + h(v₀) - h(v_k) \]

路径上的 \(h\) 被抵消,由于 \(h(v₀) - h(v_k)\) 是常数,原图与新图上任意对应两个点之间的所有路径都只相差常数,那么原图最短路径仍然是新图最短路径。

时间复杂度分析

步骤 时间复杂度
Bellman-Ford \(O(nm)\)
n 次 Dijkstra \(O(n(m + n log n))\)
总时间 $O(nm + n² log n) $
  • 适用场景:稀疏图时,时间接近 \(O(n² log n)\),远优于Floyd-Warshall的 \(O(n³)\)。稠密图上差距缩小。
DeepSeek “源神”启动!「GitHub 热点速览」
微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
DeepSeek R1 简明指南:架构、训练、本地部署及硬件要求
2 本地部署DeepSeek模型构建本地知识库+联网搜索详细步骤
2022-02-17 gcc各等级优化的性质
点击右上角即可分享
微信分享提示