Floyd-Warshall(多源最短路)
问题的提出
已知一个带权有向图,求任意两个顶点之间的最短距离
现在我们需要一个数据结构将图抽象化,本题我们使用一个
n
∗
n
n*n
n∗n 的邻接矩阵e(二维数组,该题目有4个顶点,故
n
=
4
n=4
n=4 )存储图的信息,二维数组的每个元素的取值如下:
e
[
i
]
[
j
]
=
{
0
,
i
=
j
∞
,
<
i
,
j
>
∉
e
w
i
j
,
<
i
,
j
>
∈
e
e[i][j]=\left\{ \begin{aligned} 0,&& {i=j}\\ ∞,&& {<i,j>\notin e}\\ w_{ij}, &&{<i,j>\in e} \end{aligned} \right.
e[i][j]=⎩⎪⎨⎪⎧0,∞,wij,i=j<i,j>∈/e<i,j>∈e
可到如下的二维数组:
0 | 2 | 6 | 4 |
---|---|---|---|
∞ | 0 | 3 | ∞ |
7 | ∞ | 0 | 1 |
5 | ∞ | 12 | 0 |
至此我们完成了问题的抽象化处理
运用Floyd算法求解
算法的核心步骤是:要让任意两点
a
,
b
a,b
a,b 之间的距离a->b
尽可能的小,我们需要引入第三个点
c
c
c 作为中转点,然后看看a->b->c
的值是否比a->b
小,若是则将a->b
更新为a->b->c
的值。这一过程用一专业术语描述为“松弛”。
枚举所有的点作为中转点,重复上述步骤
用图解能够更加直观地描述这一过程:
在我们之前已经构建好的数据结构中,我们可以将这一过程描述为:
对于每个
i
,
j
,
k
,
(
1
<
i
,
j
,
k
<
4
)
i, j, k,(1<i, j, k<4)
i,j,k,(1<i,j,k<4)执行e[i][j] = min(e[i][k] + e[k][j], e[i][j])
用代码实现如下:
for(int k = 1; k <= n; k++)//枚举中转点
for(int i = 1; i <= n; i++)//枚举起点
for(int j = 1; j <= n; j++)//枚举终点
e[i][j] = min(e[i][k] + e[k][j], e[i][j]);//状态更新
执行完所有步骤后,我们的邻接矩阵已经被更新为:
0 | 2 | 5 | 4 |
---|---|---|---|
9 | 0 | 3 | 4 |
6 | 8 | 0 | 1 |
5 | 7 | 10 | 0 |
这样一来,每一个e[i][j]的值都是i点到j点的最短距离了
算法评价
- 遍历所有起点 i i i 和终点 j j j 的时间复杂度 O ( n 2 ) O(n^2) O(n2),采用松弛操作,对在 i i i 和 j j j 之间的所有其他点进行一次松弛。所以总时间复杂度为 O ( n 3 ) O(n^3) O(n3);
- 可以解决带负权图的最短路问题,但不能解决带负权环图的最短路问题
- 算法易于理解,编写简单
- 较高的复杂度导致该算法不适合海量数据的处理