最短路算法
Published:
本文总结了最短路的几个经典算法。由于笔者在网上看到的很多文章都对算法流程做了详细的介绍,但笔者发现大部分文章对算法正确性并没有给出证明,而这些证明对于初次接触的人并不是显然的,因此笔者决定撰写该文章也增进自己学习理解。
大部分内容参考自 OI-wiki,且由于OI-Wiki写的较为详细,本文较为简略,但部分内容和证明笔者自认为比OI-Wiki写的更全面和直观,
最短路的重要性质
下面两个性质是基本所有最短路算法都会用到的,故列在前面。
性质1.1:三角不等式与松弛
松弛操作,是所有最短路算法的核心。
松弛操作,首先来自于最短路的三角不等式,该不等式的成立由于最短距离的定义是显然的
三角形不等式:$d(v) \leq d(u) + w(u, v)$。
而松弛操作$relax(u,v)$ 操作指:$d(v) = min(d(v), d(u) + w(u, v))$.
性质1.2
对于从$s-t$如果存在最短路径$s-x_1-x_2…x_n-t$,那么如果按照$(s,x_1),(x_1,x_2),…,(x_n,t)$的顺序对边依次进行松弛(该顺序不需要连续),那么可以找到$s-t$的最短路径。
该性质对于所有最短路算法都极为重要。
证明:归纳法证明。只要证明,按照该顺序松弛,路径上的每一个结点$u$都找到了其$d(u)$.
正权图单源最短路:Dijkstra
我们知道,使用BFS可以在无权图上寻找到最短路,其证明也是显然的。
无权图本质是边权均为1的正权图,而Dijkstra算法可以看作是BFS算法在正权图上的推广,其使用的贪心思想和BFS算法想通过,都是不断拓展距离原点最近的结点。
正确性证明
主要利用了性质1.2. 其他部分和BFS的正确性证明类似,可以由归纳法说明Dijkstra的贪心过程按照$d(u)$由小到大的顺序计算出了每个结点的$d(u)$,并且按照其最短路径松弛。较为直观,从略。
时间复杂度
简单的版本采用最小堆/最小优先队列,复杂度来源于:
- 松弛操作,更改堆元素的值
- 从堆中取出最小值
总复杂度为$O(ElgV)$
采用斐波那契堆可以拥有更小的复杂度。
负权图单源最短路:Bellman-Ford
Dijkstra算法只适用于正权图,而对于带负权的图需要另外一个算法,该算法同时可以判断最短路的存在性(也即判断图中的负环,因为有负环时沿着负环走最短路可以达到$-\infty$,故不存在最短路)。
Bellman-Ford算法,在每一轮中尝试对每条边进行松弛,总共执行$V-1$次松弛操作。
在无负环的情况下,该算法执行后所有的最短路径都被找出来了。
若执行后,还能被松弛,说明存在负环(可以无限松弛下去)。
正确性证明
同样依托于性质1.2,由于每一轮都尝试对边进行松弛,说明必然存在性质1.2中按照该顺序松弛的条件。
队列优化版本:SPFA
由于有效的松弛操作仅针对于上一轮被松驰过的结点,因此可以用一个队列记录这些结点。
该优化技术也称为SPFA。
时间复杂度
共$O(V)$轮,每轮执行$O(E)$次松弛,总复杂度为$O(VE)$.
多源最短路:Floyd
正确性证明
FLoyd算法基于DP。
首先将结点从$1..V$排序,依次考虑第$k$个结点。
定义$d_k(s,t)$为从$s$到$t$只经过$1…k$中的结点的最短距离,则$d_k$ 要么经过了第$k$个结点(也即为$d_{k-1}(s,k)+d_{k-1}(k,t)$),要么不经过(退化为$d_k-1$),则:
$ d_k(s,t) = \min(d_{k-1}(s,t) ,d_{k-1}(s,k)+d_{k-1}(k,t))$
因此经过上述DP转移公式可以计算出所有结点对的最短路。
时间复杂度
时间复杂度为$O(V^3)$。
稀疏图上的多源最短路:Johnson
JohnSon尝试将带负权的多源最短路转化为不带负权的多源最短路,然后使用$V$次Dijkstra算法求解。
证明部分同样参考自:OI-wiki
正确性证明
性质4.1:最短距离与势能
在重新标记后的图上,从 $s$ 点到 $t$ 点的一条路径 $s \to p_1 \to p_2 \to \dots \to p_k \to t$ 的长度表达式如下:
$(w(s,p_1)+h_s-h_{p_1})+(w(p_1,p_2)+h_{p_1}-h_{p_2})+ \dots +(w(p_k,t)+h_{p_k}-h_t)$
化简后得到:
$w(s,p_1)+w(p_1,p_2)+ \dots +w(p_k,t)+h_s-h_t$
无论我们从 $s$ 到 $t$ 走的是哪一条路径,$h_s-h_t$ 的值是不变的,这正与势能的性质相吻合(势能的绝对值往往取决于设置的零势能点,但无论将零势能点设置在哪里,两点间势能的差值是一定的)。
因此,我们把 $h_i$ 称为 $i$ 点的势能。
性质4.2
Johnson算法对于每一条从 $u$ 点到 $v$ 点,边权为 $w$ 的边,则我们将该边的边权重新设置为 $w+h_u-h_v$。
性质1.1告诉我们,这样子重新赋值后并没有改变结点的势能,而下面我们再证明,该赋值将使所有边权变为非负。
证明:由三角不等式(性质1.1)
根据三角形不等式,图上任意一边 $(u,v)$ 上两点满足:$h_v \leq h_u + w(u,v)$。这条边重新标记后的边权为 $w’(u,v)=w(u,v)+h_u-h_v \geq 0$。这样我们证明了新图上的边权均非负。
性质4.3
Johnson算法可以求解多源最短路。
证明:根据性质4.1,我们证明了重新标注边权后图上的最短路径仍然是原来的最短路径。根据性质4.2,我们证明了新图中所有边的边权非负,而在非负权图上,Dijkstra 算法能够保证得出正确的结果。
这样,我们就证明了 Johnson 算法的正确性。
时间复杂度
该算法的时间复杂度为$O(V)$次Dijkstra算法的复杂度,也即$O(VElgV)$.
在很多现实场景下(稀疏图),该算法优于Floyd算法。