全结点对的最短路径
图论基础知识
路径的权重等于路径上相邻节点之间的权重之和。
最短路径 δ ( u , v ) = m i n { w ( p ) : p 是 连 接 u 和 v 的 路 径 } \delta(u,v) = min\{w(p):p是连接u和v的路径\} δ(u,v)=min{w(p):p是连接u和v的路径}
最优子结构性质:最短路径的子路径也是最短路径。
证明:从u到v的最短路径必然通过一个中间节点,我们可以将路径u->v划分为u->w->v。即p=p1+p2。我们可以断言如果p是最短路径,那么p1也是u到w的最短路径。我们采用剪切-粘贴法证明,我们假设存在w’使得u到w’存在一条更短的路径,那么我们可以剪切掉p1,将p1’粘贴上,构造出了一条比p更短的路径u->w’->v。与p最优的假设矛盾。因此p1是u->w的最优路径。同理p2可证。
三角不等式: δ ( u , v ) ≤ δ ( u , x ) + δ ( x , v ) \delta(u,v) \leq \delta(u,x) + \delta(x,v) δ(u,v)≤δ(u,x)+δ(x,v)。
如果图G包含一条负回路,那么最短路径不存在。(我只要一直绕着回路走,路径会越来越小)
动态规划
为了简化表示,建立nn的邻接矩阵,定义如下:
w
i
j
=
{
0
i
=
j
w
(
i
,
j
)
(
i
,
j
)
∈
E
+
i
n
f
(
i
,
j
)
∉
E
w_{ij} = \left\{ \begin{matrix} 0 \quad i=j \\ w(i,j) \quad (i,j) \in E \\ +inf \quad (i,j) \notin E \end{matrix} \right.
wij=⎩⎨⎧0i=jw(i,j)(i,j)∈E+inf(i,j)∈/E
输出nn矩阵D,
d
i
j
d_{ij}
dij表示点i到j的最短路径。
令 d i j ( m ) d_{ij} ^{(m)} dij(m)表示从点i到j最多包含m条边的最短路径。可以证明 d i j n − 1 d_{ij}^{n-1} dijn−1就是原问题的解。
证明从i到j的最短路径最多包含n-1条边。
因为所有的回路的权重之和都是正数,所以最短路径肯定不包含回路,一条不包含回路的路径最多有n-1条边。
考虑递归公式:
d i j ( m ) d_{ij}^{(m)} dij(m)有两种情况,(1)最多有m-1条边(2)有m条边
(1) d i j ( m ) = d i j ( m − 1 ) + w j j d_{ij}^{(m)} = d_{ij}^{(m-1)} + w_{jj} dij(m)=dij(m−1)+wjj
(2)令k为最短路径中j前面的点。 d i j ( m ) = d i k ( m − 1 ) + w k j d_{ij}^{(m)} = d_{ik}^{(m-1)}+ w_{kj} dij(m)=dik(m−1)+wkj
综上: d i j ( m ) = m i n 1 ≤ k ≤ n { d i k ( m − 1 ) + w k j } d_{ij}^{(m)} = min_{1\leq k \leq n} \{d_{ik}^{(m-1)} + w_{kj}\} dij(m)=min1≤k≤n{dik(m−1)+wkj}
时间复杂度 O ( n 4 ) O(n^4) O(n4):总共需要遍历n-1次得到答案,每次遍历需要确定 n 2 n^2 n2个值,每个值需要考虑n种可能。
空间复杂度 O ( n 3 ) O(n^3) O(n3): n-1 个 n * n矩阵。
优化空间复杂度 O ( n 2 ) O(n^2) O(n2):其实每次只需要最初的W 和 D ( m − 1 ) D^{(m-1)} D(m−1)
时间效率优化:重复平方
对
s
≥
1
,
D
(
2
s
)
s\geq 1,D^{(2s)}
s≥1,D(2s)可以通过以下方式计算:
d
i
j
(
2
s
)
=
m
i
n
1
≤
k
≤
n
{
d
i
k
(
s
)
+
d
k
j
(
s
)
}
d_{ij} ^ {(2s)} = min_{1\leq k \leq n} \{d_{ik}^{(s)} + d_{kj}^{(s)}\}
dij(2s)=min1≤k≤n{dik(s)+dkj(s)}
因此可以按照以下顺序计算
D
(
2
)
,
D
(
4
)
,
D
(
8
)
,
…
,
D
(
2
[
l
o
g
n
]
)
=
D
(
n
)
D^{(2)},D^{(4)},D^{(8)},\dots,D^{(2^{[logn]})} = D^{(n)}
D(2),D(4),D(8),…,D(2[logn])=D(n)
时间复杂度 O ( n 3 l o g n ) O(n^3logn) O(n3logn)
Floyd-Warshell算法
最短路径的结构:
-
不会包含同一个节点两次
-
中间节点要么在最短路径上,要么不在。
d i j ( k ) = m i n { d i j ( k − 1 ) , d i k ( k − 1 ) + d k j ( k − 1 ) } d_{ij}^{(k)} = min\{d_{ij}^{(k-1)},d_{ik}^{(k-1)} + d_{kj}^{(k-1)}\} dij(k)=min{dij(k−1),dik(k−1)+dkj(k−1)} -
D ( 0 ) D^{(0)} D(0)就是权重矩阵,可以通过 D ( k − 1 ) D^{(k-1)} D(k−1)计算 D ( k ) D^{(k)} D(k)
Floyd_Warshall(w,n)
for i=1 to n
for j=1 to m
d[i,j] = w[i,j]
pred[i,j]=null
for k=1 to n //首先遍历中间节点
for i=1 to n
for j=1 to n
if d[i,j]<d[i,k]+d[k,j]
d[i,j] = d[i,k] + d[k,j]
pred[i,j]=k
时间复杂度 Θ ( n 3 ) \Theta(n^3) Θ(n3)