“0–1 BFS在零一边权下用deque保持两个相邻距离层;Dial算法将其推广到有限整数窗口,radix heap再按二进制差异跳过空键域。三者保留本页最小有效键结算的责任,不能因换队列而忽…”
从起点和终点同时找路,可能比只向前扩张更早得到一条完整路线。但“两边碰到了”只说明找到一个可行答案,并没有自动比较尚未碰到的路线。双向Dijkstra需要同时维护两件东西:已经找到的最好路径有多长,以及继续搜索还可能得到多短。
形式陈述
正向距离与反向距离
给定有限有向图,边权非负,查询从s到t的一条最短路。前向搜索在原图上从s运行Dijkstra,距离记为
两边各有自己的最小优先队列、已结算集合
维护
用已结算的跨边生成上界
当前向结算u并扫描原边
对应一条真实完整路线。若它小于μ,就更新μ并记下连接边
这里使用已结算端点,是为了使保存的两段距离与父边都不会再改变。用有限的暂定距离也能构造可行上界,但需要另外维护当时路径见证;本页实现不混用这两个版本。
停止条件
先从两个队列头删除已过时或已结算的记录,令
若队列非空且
便可返回保存的最好路线。没有有效项的一侧视为已经完成其所有可达点;本页逐轮交替扩展,若某侧为空也可结束,并按μ是否有限决定有路或不可达。空队列边界的理由见下文,而不是让程序永远等两边相遇。
直觉
μ是上界,两个队首提供另一侧证据
每次更新μ都有两段已结算路径与一条真实连接边,因此μ从不小于真正最短距离。它只能告诉我们“已经有这么短的一条路”。
Dijkstra的结算性质还保证:尚未前向结算的可达顶点,到s的真实距离不小于α;尚未后向结算的顶点,到t的真实距离不小于β。否则该点更短的路径上会有一个更小的有效队列候选,违背队首最小性。这个下界针对未结算区域,不是说两边各自的全部距离都已求完。
为什么队首之和足以停止
反设存在一条长度
只要两边各自已开始扫描,s属于
若刚开始只有一边扫描过源点,μ仍无穷,两个有限队首不会触发上述有限上界停止。某侧此时已空,只可能它的起点没有可继续到达目标的路线,s=t已在入口单独处理。之后若一侧队列耗尽,另一侧起点早已结算:若有s到t路径,沿这条路径必有一个跨边候选被检查,最优路线已进入μ;若没有,μ保持无穷。
执行骨架与可运行版本
若 s=t,返回零和 [s]
构建反向邻接表;初始化两个距离表、队列和结算集合
μ ← 无穷;连接证据 ← 空;方向 ← 前向
重复:
丢弃两队头的旧快照与已结算项
若任一队为空,退出
若 min(QF)+min(QB) ≥ μ,退出
从当前方向取最小有效项 (d,u),结算 u
若 u 在另一方向已结算,检查同点连接的完整费用
对当前方向 u 的每条边:
若边的另一端在对方已结算,检查跨边完整费用
执行当前方向的严格松弛,更新父边并加入新快照
切换方向
若 μ=无穷,返回无穷和空路径
否则沿保存的连接证据,拼接前向父链与反向后继链
完整Python实现与测试使用精确非负整数权,包含反图构造、旧项清理、父边恢复和零费用重复环删除。数学停止条件适用于精确非负实数权;浮点实现的舍入、溢出或NaN需要单独处理,不能把近似比较当成同一个证明。
例子与边界
同一整数图上,先找到八,再找到四
使用Dial页的图:
| 扫描方向与顶点 | 新的完整路线信息 |
|---|---|
| 前向s,距离0 | 尚未连接,μ=∞ |
| 后向t,距离0 | 反图发现c的距离2、a的距离6 |
| 前向b,距离1 | 改进a为2、c为6,仍未连接已结算后向点 |
| 后向c,距离2 | b已前向结算,经 |
| 前向a,距离2 | c已后向结算,经 |
清理旧项后,两队最小有效键都是二。
第一次相遇的点不一定在最短路上
取
正确算法前向结算b时,t早已后向结算,跨边
要区分两句话:第一次相遇后只返回经过相遇点的路径可能错误;若一直维护所有跨边的最好μ,经典的双方已扫描点相遇停止法本身也可以正确,只是常晚于队首之和停止。[1] 不能把第一种错误泛化成“任何相遇停止都错”。
反图不是可省的技巧
只有边
零权边与零权圈仍合法,队首之和可以等于μ,等号足以停。负边会破坏两侧结算下界,即使原图没有负圈也不能直接套用。只需要单对点查询是本页的接口;提前停止时,其他顶点的暂定距离通常尚未最优,不能把它们当作完整单源答案返回。
推论与应用
路径重建与成本
以下时间界按单位成本RAM计:顶点下标、有限距离及中间距离和须装入可操作的机器字,加法、比较和所用队列基本操作按各自已声明成本收费。若权重或累计费用是任意长整数,须另计其位运算成本;这与radix heap页对Word-RAM及最高置位指令的要求相衔接。
前向父链从连接边起点u倒推到s;反向父链从连接边终点v按原图方向走向t。连接处只拼接一次。两段若再次经过同一顶点,形成的重复圈必为零费用,否则删圈会得到比已证明最优的μ更短的路;按首次出现位置删除这些零圈,可在O(n)时间得到简单路径。
每个方向至多结算n点、扫描m条边,反图构造为O(n+m)。使用二叉堆与惰性重复记录,插入、弹出总数为O(m+1),两边合计的保守界是
时间与O(n+m)辅助空间。双向搜索在某些图上会少扫描许多顶点,但一般最坏渐近界并未因此改善;有向度分布偏斜时,也不保证两边探索范围一样大。
单元终结任务:用证书区分四种队列选择
先对0–1 BFS页的零一图交出距离
- Dial的槽一怎样先装距离一、后装距离八;解释为什么清空旧项后游标可到八而最终最短距离最大只有四
- Radix heap的last从二改为四时,键4、6、4分别降到哪个桶,键八为何不用搬
- 双向搜索在μ从八改为四后,给出两队最小有效键二和二,以及连接边
;证明此时停止无需等待双方在同一点结算
最后分别拒绝三种非法改动:让零一队列直接接受权二;让radix heap在last=4后插入三;让反向Dijkstra在原有向图沿出边行走。每次都应指出被破坏的不变量,而不是只说“换一种算法”。
参考资料
- [1] Andrew V. Goldberg, Point-to-Point Shortest Path Algorithms, SOFSEM2007,§2,PDFpp2–3:反图搜索、跨已扫描区域的μ更新、相遇停止与更强队首和停止。本文用一组小整数图完整复算两者区别。
- Peter Sanders, Kurt Mehlhorn, Martin Dietzfelbinger and Roman Dementiev, Sequential and Parallel Algorithms and Data Structures: The Basic Toolbox, Ch.10, 2019,§10.3的最小暂定距离结算证明,作为本页两侧下界的基础。