“本页受限最短路子程序使用Dijkstra,因此权重非负。Yen原方法可以搭配其他适用的最短路子程序,本页没有因此允许把负边直接交给Dijkstra。[1]”
形式陈述
给定有限有向或无向图、源点
每个有限
故
算法以按键取最小值的优先队列实现。设
- 二叉堆加顶点句柄执行至多
次extract-min、至多 次decrease-key,最坏时间 、额外空间 ; - 不支持
decrease-key时可插入新记录并惰性跳过旧记录,从单个源记录开始,总共插入至多 个堆项,时间 、空间 ; - Fibonacci 堆的摊还操作界给出整个算法确定性最坏总时间
; - 邻接矩阵配合线性扫描最小未结算键,确定性最坏时间为
、额外空间 (不计矩阵本身)。
直觉
Dijkstra 把已结算区看成从源点扩张的距离球。堆中每个键代表一条从球内跨出到该顶点的最佳已知路线;取最小键就是选择下一层边界。由于边权不为负,任何尚未进入球的绕行都不可能先走得更远、再以负代价回来改短已结算点。
松弛负责生成与更新候选,贪心选择负责宣布一个候选不再变化。只做松弛而没有最小键次序,是另一类标签修正算法;只取最小键而不扫描出边,也无法把正确距离传播给后继。
例子与边界
在边
上,结算
负边反例不需要负圈。取
算法先结算
负权图可改用Bellman–Ford 算法。零权边和零权圈不破坏正确性,但可能产生多个相同键;平局以任意顺序结算都安全。不可达顶点始终为
推论与应用
Dijkstra 解决非负权最短路问题;图表示决定能否只扫描现有边,队列实现决定最小键与减键成本。若只查询一个目标
0–1 BFS在零一边权下用deque保持两个相邻距离层;Dial算法将其推广到有限整数窗口,radix heap再按二进制差异跳过空键域。三者保留本页最小有效键结算的责任,不能因换队列而忽略旧项、键范围或字级成本。单对点查询还可采用双向Dijkstra,在反图同时搜索,保存跨边可行上界并用两队首之和证明停止。
Johnson 算法先用势函数把含负边、无负圈的图重赋为非负权,再逐源调用 Dijkstra。A*在一致启发函数下等价于对约化非负权运行同一结算逻辑;对同一个固定目标和“目标结算即停止”的接口,令启发函数
参考资料
- Edsger W. Dijkstra, “A Note on Two Problems in Connexion with Graphs,” Numerische Mathematik 1, 1959, pp. 269–271。
- Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest, and Clifford Stein, Introduction to Algorithms, 4th ed., MIT Press, 2022,§22.3。
- Jon Kleinberg and Éva Tardos, Algorithm Design, Pearson, 2005,§4.4。