Johnson 全源负权最短路径算法详解
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)\) 均为非负。且满足“原图的最短路同样是新图的最短路”
4 运行Dijkstra算法
对调整后的图,为每个节点 \(u\) 运行一次Dijkstra算法,得到最短路径 \(d'(u, v)\)。
5 还原原始最短路径
原始图中 \(u\) 到 \(v\) 的最短路径为:
为什么是对的?
1 边权调整的非负性
\(h\) 是虚拟点到节点的距离,根据 Bellman-Ford 的最短路径性质,对任意边 \((u, v)\) 有:
移项得:
因此,调整后的权重 \(w'(u, v)\) 非负,Dijkstra算法可正确运行。
2 最短路径的等价性
设原图中一条路径 \(p = v₀ → v₁ → ... → vₖ\) 的权重和为:
调整后的权重和为:
路径上的 \(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³)\)。稠密图上差距缩小。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
DeepSeek R1 简明指南:架构、训练、本地部署及硬件要求
2 本地部署DeepSeek模型构建本地知识库+联网搜索详细步骤