Floyd-Warshall(多源最短路)
问题的提出
已知一个带权有向图,求任意两个顶点之间的最短距离
现在我们需要一个数据结构将图抽象化,本题我们使用一个 n∗nn*nn∗n 的邻接矩阵e(二维数组,该题目有4个顶点,故 n=4n=4n=4 )存储图的信息,二维数组的每个元素的取值如下:
e[i][j]={0,i=j∞,<i,j>∉ewij,<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,ba,ba,b 之间的距离a->b
尽可能的小,我们需要引入第三个点 ccc 作为中转点,然后看看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点的最短距离了
算法评价
- 遍历所有起点 iii 和终点 jjj 的时间复杂度 O(n2)O(n^2)O(n2),采用松弛操作,对在 iii 和 jjj 之间的所有其他点进行一次松弛。所以总时间复杂度为 O(n3)O(n^3)O(n3);
- 可以解决带负权图的最短路问题,但不能解决带负权环图的最短路问题
- 算法易于理解,编写简单
- 较高的复杂度导致该算法不适合海量数据的处理