稀疏图上更快的单源最短路算法

· · 个人记录

TL;DR:这是一个求解无向图(非负实数边权)上单源最短路问题,期望复杂度为 O(n \sqrt{\log n \log \log n}) 的非确定性做法。(以下讨论均默认 n,m 同阶)

做法来源:WC 2025 讲课。原论文见 link。

回忆 dijkstra 为什么无法突破 O(n \log n):注意到 dijkstra 中保证了答案是按照最短路长度从小到大的顺序被确定的,也就是我们做了 \text{DO\tiny{(Distance Ordering)}} 而非 \text{SSSP\tiny{(Single Source Shortest Path)}},并且事实上前者需要做实数排序,因此更难。

那么如何绕开排序呢?一个想法是,我们选出若干个关键点,然后把剩下的点挂在关键点上,关键点间按照最短路从小到大做,剩下的点跟着关键点更新即可。由于关键点数量是 o(n),所以我们的复杂度有希望低于 O(n \log n)

事实上,这一算法就是这么做的。

默认图连通,定义 dis_{u,v} 为图上 uv 的最短路径。不妨假设将 dis 赋予第二关键字——路径中经过的边数,第三关键字——路径终点编号大小。不难发现这样 dis 两两不同,并且 dijkstra 求出的确实可以求出符合这一定义的最短路。

设定阈值 B,考虑在图上令每个点以 \frac{1}{B} 的概率成为关键点。定义关键点集合 R。接下来考虑每个非关键点 u

此外,对于关键点 p,定义 \text{Bundle}_p=\{u|b_u=p\}

考虑如何求出 \text{Ball}\text{Bundle}。直接对每个非关键点跑 dijkstra 就好了……吗?不难发现如果来个菊花复杂度就爆了。我们只能接受每个点度数是常数的图。

所以在运行这一算法前,我们要先对图结构做一些改造。对于一个原图上度数为 d 的点我们把他拆成 d 个新点然后用一条链串起来。每连一条边我们就从两个点对应的新点里面选一个没用过的连起来。这样度数就对了。

好了我们现在在期望 O(nk \log k) 的时间内建出来了我们要的结构。回顾我们想要的过程:

下面是算法过程,证明有空补:

算一下复杂度,这里的复杂度是 O(\frac{n}{B} \log \frac{n}{B}+nB)。平衡一下就是开头那个复杂度。

代码并不是特别难写。常数还行,不过也不是特别小。空间常数很大。代码可以见 loj。

upd:没用 O(1) dec-key 的堆,可能复杂度不太对。看的时候自行脑补一下就好了。