算法简介
F
l
o
y
d
Floyd
Floyd算法是多源最短路径算法,即可以求任意两点的最短路径,它基于动态规划的思想,时间复杂度为
O
(
n
3
)
O(n^3)
O(n3)。
它的创始人罗伯特·弗洛伊德
(
R
o
b
e
r
t
W
.
F
l
o
y
d
)
(Robert\ W.Floyd)
(Robert W.Floyd)将此算法命名为
F
l
o
y
d
−
W
a
r
s
h
a
l
l
Floyd-Warshall
Floyd−Warshall算法,简称
F
l
o
y
d
Floyd
Floyd算法。罗伯特·弗洛伊德是1978年图灵奖得主,他同时还创立了堆排序算法。
算法思想
F l o y d Floyd Floyd算法的核心思想就是用每个点作为中间结点去更新任意点的最短路径。
它的核心思想是 d p [ k ] [ i ] [ j ] = m i n ( d p [ k − 1 ] [ i ] [ j ] , d p [ k − 1 ] [ i ] [ k ] + d p [ i − 1 ] [ k ] [ j ] ) dp[k][i][j]=min(dp[k-1][i][j],dp[k-1][i][k]+dp[i-1][k][j]) dp[k][i][j]=min(dp[k−1][i][j],dp[k−1][i][k]+dp[i−1][k][j])
其中 d p [ 0 ] [ i ] [ j ] = m a p [ i ] [ j ] dp[0][i][j]=map[i][j] dp[0][i][j]=map[i][j]也就是初值为邻接矩阵。
核心代码
假设目前 m a p [ 0 ] [ ] [ ] map[0][\ ][\ ] map[0][ ][ ]存的是邻接矩阵。
void Floyd(){
for(int k=1;k<=n;k++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
map[k][i][j]=min(
map[k-1][i][j],
map[k-1][i][k]+map[k-1][k][j]
);
}
}
}
}
值得注意的是 k k k在最外层,这是因为 F l o y d Floyd Floyd本质是动态规划算法,做的实际上是二维动态规划。第一个维度的 k k k只表示第 k k k次动态规划的结果,而第二个第三个维度的 k k k则表示以第 k k k个点作为中间结点。
优化
F
l
o
y
d
Floyd
Floyd算法可以在空间上进行优化,这才是平常使用的
F
l
o
y
d
Floyd
Floyd算法。
d
p
[
k
]
[
i
]
[
j
]
=
m
i
n
(
d
p
[
k
−
1
]
[
i
]
[
j
]
,
d
p
[
k
−
1
]
[
i
]
[
k
]
+
d
p
[
i
−
1
]
[
k
]
[
j
]
)
dp[k][i][j]=min(dp[k-1][i][j],dp[k-1][i][k]+dp[i-1][k][j])
dp[k][i][j]=min(dp[k−1][i][j],dp[k−1][i][k]+dp[i−1][k][j])中,在第
k
k
k轮时,与
k
k
k相关的路径长度是不会改变的,所以无需保存前一个状态。
void Floyd(){
for(int k=1;k<=n;k++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
map[i][j]=min(
map[i][j],
map[i][k]+map[k][j]
);
}
}
}
}
总结
F l o y d Floyd Floyd算法的因为要求任意两点最短路径,所以空间复杂度就是存图的 O ( n 2 ) O(n^2) O(n2),因为三重循环则导致了时间复杂度为 O ( n 3 ) O(n^3) O(n3)。 F l o y d Floyd Floyd算法适用于带负权的图,但不能出现负权环。因此, F l o y d Floyd Floyd算法不适用于大量数据的计算,他简单易实现的同时也注定了效率上得做取舍。