开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第7天,点击查看活动详情
Floyd算法
Floyd算法是求解多源最短路径问题的典型算法,可以知道图中任意两点之间的最短路径。该算法对于有向图、无向图都适用,同时允许图中带有负权边,但是不允许有负权环。
Floyd算法采用动态规划的思想,分为多个阶段来解决问题。
若图G有n个顶点(V0∼Vn−1),则将求图中每一对顶点之间的最短路径分n个阶段∶
Floyd求解过程:
-
首先进行初始化,在没有其它顶点中转的情况下,求得各顶点间的最短路径;
-
在各顶点间增加V0作为中转结点,求得各顶点间新的最短路径;
-
再增加V1作为中转结点,求得各顶点间新的最短路径;
……
-
最后增加Vn−1作为中转结点,求得各顶点间最终的最短路径。
3.1 算法思想
Floyd只能使用邻接矩阵来实现。
为了方便理解,我们来手动模拟一下实现过程。以有向图演示,无向图同理。
我们使用两个大小为n×n的二维数组分别记录最短路径dis与中转顶点path。其中,最短路径矩阵可以告诉我们任意两顶点间的最短距离;而中转顶点矩阵可以告诉我们路径。
(1)初始化
初始化的最短路径矩阵其实就是邻接矩阵,中转顶点矩阵全部标记为−1,代表未经过中转。
(2)求解
① 加入V0中转
可以看到,V0顶点的入度为0,所以任何顶点都不能到达V0,最短路径与中转顶点矩阵不变。
没有别的顶点可以通过V1中转或使得dis减少,进行下一次中转。
② 加入V1中转
可以看到,当我们添加到V1作为中转时,
原先V2→V3=∞,现在V2→V1→V3=2,更新dis[V2][V3]=2,path[V2][V3]=1
原先V2→V4=7,现在V2→V1→V4=6,更新dis[V2][V4]=6,path[V2][V4]=1
没有别的顶点可以通过V1中转或使得dis减少,进行下一次中转。

③ 加入V2中转
可以看到,当我们添加到V2作为中转时,
原先dis[V0][V1]=∞,现在dis[V0][V2]+dis[V2][V1]=2,更新dis[V0][V1]=2,path[V0][V1]=2
原先dis[V0][V3]=∞,现在dis[V0][V2]+dis[V2][V3]=3,更新dis[V0][V3]=3,path[V0][V3]=2
原先dis[V0][V4]=10,现在dis[V0][V2]+dis[V2][V4]=7,更新dis[V0][V4]=7,path[V0][V4]=2
没有别的顶点可以通过V2中转或使得dis减少,进行下一次中转。

④ 加入V3中转
可以看到,当我们添加到V3作为中转时,
原先dis[V0][V4]=7,现在dis[V0][V3]+dis[V3][V4]=4,更新dis[V0][V4]=4,path[V0][V4]=3
原先dis[V1][V4]=5,现在dis[V1][V3]+dis[V3][V4]=2,更新dis[V1][V4]=2,path[V1][V4]=3
原先dis[V2][V4]=6,现在dis[V2][V3]+dis[V3][V4]=3,更新dis[V2][V4]=3,path[V1][V4]=3
没有别的顶点可以通过V3中转或使得dis减少,进行下一次中转。

⑤ 加入V4中转
可以看到,当我们添加到V4作为中转时,由于V4的出度为0,故不会进行更新,且已经将所有顶点中转完成,得到的便是最终结果。
(3)输出
dis[i][j]存储的便是Vi∼Vj的最短路径长度。
而想要输出Vi∼Vj的最短路径,则需要顺着path数组往前找。
以上图的V2∼V4顶点为例:
首先path[V2][V4]=3,则说明经过V3进行中转,路径为V2→(V3)→V4
接着找path[V2][V3]=1,则说明经过V1进行中转,路径为V2→(V1)→V3→V4
接着找path[V2][V1]=−1,则说明没有经过任何顶点进行中转,得到最终的路径为V2→V1→V3→V4
3.2 实现
给出核心部分的C语言代码:
for (k = 0; k < VertexNum; k++)
{
for (i = 0; i < VertexNum; i++)
{
for (j = 0; j < VertexNum; j++)
{
if (dis[i][k] + dis[k][j] < dis[i][j])
{
dis[i][j] = dis[i][k] + dis[k][j];
path[i][j] = k;
}
}
}
}
3.3 算法分析
估计这时候你也看出了一些问题,我使用Dijkstra算法将每个顶点作为起点计算一遍,时间复杂度不也是O(∣V∣3)吗?那Floyd算法的优势在哪里呢?
其实,虽然两种算法都是O(∣V∣3),但是前面的系数并不相同,Floyd的系数会更小一些,所有效率也会更高一些。也因此,即使它的复杂度到达了O(∣V∣3)的程度,对于一些中小规模的图仍然是适用的。
同时Floyd也支持负权边,也是其一个优点。