Bellman Ford Algorithm
- 单源最短路问题定义
- 输入:有向图,已知各边长度,以及源点 s s s
- 输出:计算从源点出发,到达图中个点最短路的长度
- Dijkstra算法的问题
- 对于存在负权边的情形,并不总是正确的
- 并不是十分的分布式
- 对于负权环的问题
- 方案1:允许负权环的存在——得不到最短路
- 方案2:要求无环最短路的计算——汉密尔顿遍历问题,NP完全问题
- 方案3:允许负权边,但不允许负权环——BF算法
- 目标
- 计算所有顶点的单源最短路径长度——BF算法
- 或者输出负环
- 最优子结构
- 图本身不好描述相对顺序
- 路径的顺序比较明确
- 问题大小的界定——路径的边个数
- P P P:最多 i i i条边的限制下, s → v s \to v s→v的最短路径长度
- case 1:如果 P P P有最多 i − 1 i - 1 i−1条边,那么其必然是 s → v s \to v s→v的最短路径,拥有最多 i − 1 i - 1 i−1条边
- case 2:如果 P P P有 i i i条边,其中最后一条为 w → v w \to v w→v,那么除去最后一条边的 P ′ P^\prime P′即为 s → w s \to w s→w的 i − 1 i - 1 i−1条边的最短路
- 最优子结构条件:允许环路(由于边数限制,不会无限循环),未达节点的最短路长度为 + ∞ + \infty +∞
-
L
i
,
v
=
min
{
L
i
−
1
,
v
,
min
(
w
,
v
)
∈
E
{
L
i
−
1
,
w
+
c
w
,
v
}
}
L_{i, v} = \min \{L_{i - 1, v}, \min_{(w, v) \in E} \{L_{i - 1, w} + c_{w, v}\}\}
Li,v=min{Li−1,v,min(w,v)∈E{Li−1,w+cw,v}}
- 一个子问题只需要 ( 1 + indegree(v) ) (1 + \operatorname{indegree(v)}) (1+indegree(v))次搜索
- 如果没有负权环,那么我们一定能在 n − 1 n - 1 n−1条边内找到最短路,且不会有环路(环路只会增加路径长度),这种情况下和其他dp算法无异
- 算法(不考虑负权环)
- 初始化: A [ 0 , s ] = 0 A[0, s] = 0 A[0,s]=0, A [ 0 , v ] = + ∞ A[0, v] = +\infty A[0,v]=+∞
- 循环:
i
=
1
,
…
,
n
−
1
i = 1, \dots, n - 1
i=1,…,n−1,
v
∈
V
v \in V
v∈V
- A [ i , v ] = min { A [ i − 1 , v ] , min } A[i, v] = \min \{ A[i - 1, v], \min \} A[i,v]=min{A[i−1,v],min}
- 时间复杂度: O ( m n ) O(mn) O(mn)(考虑最后实际的计算量只有 O ( n + n ∑ v indgree(v) ) O(n + n \sum_v \operatorname{indgree(v)}) O(n+n∑vindgree(v)))
- 一个优化手段(保证达不到
O
(
n
2
)
O(n^2)
O(n2)):提前终止
- 在某一次 i i i的迭代中,如果所有的 A [ i , v ] = A [ i − 1 , v ] A[i, v] = A[i-1, v] A[i,v]=A[i−1,v]都成立,则终止程序
- 如果输入的图确实有负权环怎么办?
- 定理:图 G G G没有负权环,当且仅当在BF算法中, A [ n − 1 , v ] = A [ n , v ] A[n - 1, v] = A[n, v] A[n−1,v]=A[n,v]
- 结论:运行BF算法之后,检查 A [ n − 1 , v ] A[n - 1, v] A[n−1,v]与 A [ n , v ] A[n, v] A[n,v]是否相同,已确定图中是否有无权环
- 时间复杂度 O ( m n ) O(mn) O(mn)
- 极端情况: s s s与任何其他点没有边相连,且其他点共同组成一个 负权环——加入一个零距离的虚拟节点
- 空间优化
- 实际上,我们在计算当前迭代最优解时只需要前一次迭代的结果
- 空间优化可以达到 O ( n ) O(n) O(n)
- 问题:如何在优化后的模式中重建最优解
- 计算另外一个表 B B B,其中 B [ i , v ] B[i,v ] B[i,v]表示 s s s到 v v v的不超过 i i i条边上的最短路的倒数第二个节点(前序指针)——重建时,逆序沿着前序指针得到最优解
- 可以利用这个逆序指针辅助检查负权环:迭代过程中 B B B检查到环,必然是一个负权环
All Pairs Shortest Paths
-
问题定义
- 输入:图(允许负权边)
- 输出:计算所有点对之间的最短路长度 或者 报告图中存在负权环
-
直接使用单源最短路算法?时间复杂度太高,含负权边的稠密图( n n n遍BF)可以达到 O ( N 4 ) O(N^4) O(N4)
-
Floyd-Warshall算法: O ( N 3 ) O(N^3) O(N3)复杂度
-
最优子结构(不考虑负权环)
- P P P为固定的源点 i i i和目标点 j j j,使用任意中间点 V ( k ) V^{(k)} V(k)
- case 1:点 k k k不在 P P P中,那么 P P P是使用任意中间点 V ( k − 1 ) V^{(k - 1)} V(k−1)的最短路
- case 2:点 k k k在 P P P中,那么 P 1 P_1 P1为 i i i到 k k k的 V ( k − 1 ) V^{(k - 1)} V(k−1)的最短路, P 2 P_2 P2为 k k k到 j j j的 V ( k − 1 ) V^{(k - 1)} V(k−1)最短路
-
算法
- 三维数组 A A A, A [ i , j , k ] A[i, j, k] A[i,j,k]表示使用节点 1 , … , k {1, \dots, k} 1,…,k实现的 i i i到 j j j的最短路径
- 初始化,对 i = j i = j i=j,置0;对 i ≠ j , k = 0 , ( i , j ) ∈ E i \neq j, k = 0,(i, j) \in E i=j,k=0,(i,j)∈E,置 c i j c_{ij} cij;对 i ≠ j , ( i , j ) ∉ E i \neq j, (i, j) \notin E i=j,(i,j)∈/E,置 + ∞ +\infty +∞
- 三重循环
k
,i
,j
:- A [ i , j , k ] = min { A [ i , j , k − 1 ] , A [ i , k , k − 1 ] + A [ k , j , k − 1 ] } A[i, j, k] = \min \{A[i, j, k - 1], A[i, k, k - 1] + A[k, j, k - 1] \} A[i,j,k]=min{A[i,j,k−1],A[i,k,k−1]+A[k,j,k−1]}
- 时间复杂度 O ( N 3 ) O(N^3) O(N3)
-
如何检查负权环?检查对角线,如果存在 A [ i , i , n ] < 0 A[i, i, n] < 0 A[i,i,n]<0,那么存在负权环
-
解重建
- 除了 A A A本身,还需要计算一个 B B B,表示 i i i和 j j j最短路上最大的标签
- 在第二个情景,需要将 B B B重置为对应的 k k k
- 得到最大点之后,在ik,kj之间继续寻找最短路
-
Johnson算法:归约到1次BF调用, n n n次Dijkstra调用
-
重加权:对于节点 u u u和 v v v,定义其权重 p u p_u pu和 p v p_v pv,对于其边 < u , v > <u,v> <u,v>权 c e c_e ce,定义新的边权重 c e ′ = c e + p u − p v c_e^\prime = c_e + p_u - p_v ce′=ce+pu−pv
- 性质:对所有调整后的边,对 s s s和 t t t之间的所有路径,其路径权重只变化 p s − p v p_s - p_v ps−pv
- 结论:上述重加权过程不会影响最短路结果
- 思路:使用这种重加权方法对负权环进行处理——需要考虑点权重的获得
-
点权重获得和重加权
- 设置一个虚拟节点 s s s,其到所有既有节点的距离为0
- 使用BF算法,计算 s s s到各点 v v v的最短距离
- 该距离即为对应既有点的权重 p v p_v pv
- 根据所有的点权重,定义 c e ′ = c e + p u − p v c_e^\prime = c_e + p_u - p_v ce′=ce+pu−pv
-
通过这样的方式,将所有的边的权重处理为非负,同时不改变最短路结果,在可行的情况下可以采用更快的Dijkstra算法
-
Johnson算法
- 输入:可能含有负权环的有向加权边图 G G G
- 建立一个虚拟节点 s s s,其到达所有的点的距离均为0
- 在该新图上运行BF算法,计算从 s s s到达各店的最短路(在此阶段即可判断是否存在负权环并终止算法)
- 根据上述描述确定各点权重,并更新边权
- 接下来可以运行 n n n次Dijkstra算法计算最短路
- 在得到最短路之后,将最短路 d ′ ( u , v ) d^\prime(u,v) d′(u,v),减去变化的权重得到最终得结果 d ( u , v ) = d p r i m e ( u , v ) − p u + p v d(u, v) = d^prime(u, v) - p_u + p_v d(u,v)=dprime(u,v)−pu+pv
-
时间复杂度(稀疏图): O ( n m log n ) O(nm \log n) O(nmlogn)
-
新边权非负性保证
- 已知新点权 p v p_v pv和 p u p_u pu
- P P P为到达 u u u的最短路,长度显然为 p u p_u pu
- 针对边 ( u , v ) (u, v) (u,v),存在一条到达 v v v的路径 p u + c u v p_u + c_{uv} pu+cuv
- 根据最短路性质 p v ≤ p u + c u v p_v \le p_u + c_{uv} pv≤pu+cuv
- 则有 c u v ′ = p u + c u v − p v ≥ 0 c^\prime_{uv} = p_u + c_{uv} - p_v \ge 0 cuv′=pu+cuv−pv≥0