Floyd 算法
前言
DP 魅力时刻
1. 原理
Floyd 算法依然使用松弛操作求短路,不同的是此算法使用动态规划算法实现松弛操作。
考虑松弛操作的本质,其就是在在已知的路径中加入一个新的节点,加入后可以让路径长度更短的操作。
那么我们考虑任意两个节点,只需要枚举所有的节点,逐个尝试松弛两个节点的路径,如果松弛后路径长度更短则更新现有的路径,也就是当开始节点到结束节点的当前距离大于开始节点到松弛节点与松弛节点到结束节点的路径长度之和,那么就更新当前两节点的距离为经过松弛节点的距离。
更深入的理解,此算法每一次允许一个新的节点加入两点之间可能的最短路中,通过长度的判断选择更新距离。
2. 实现
定义 DP 数组 disr[i][j] 表示节点 \(i\) 与节点 \(j\) 之间的最短路,可以写出如下代码:
memset(dist,0x3f,sizeof dist);//初始化所有节点的最短路为无穷大
for(int i=1;i<=m;i++){//直接将输入的边的信息作为 DP 初值
int u=rd,v=rd,w=rd;
dist[u][v]=w;
dist[v][u]=w;
}
for(int k=1;k<=n;k++){//枚举添加的点
for(int i=1;i<=n;i++){//枚举起始点
for(int j=1;j<=n;j++){//枚举终点
dist[i][j]=min(dist[i][j],dist[i][k]+dist[k][j]);//状态转移
}
}
}
可见其时间复杂度为 \(O(N^3)\) 其中 \(n\) 为图中节点个数。
3. 应用
3.1 判断图中的负环
在 Floyd 算法执行完成后,如果对于任意编号为 \(i\) 的节点,出现了 \(dist_{i,i}<0\),则图中有负环。
为什么呢?
根据负环的定义,负环上的边权和小于 \(0\)。
则考虑负环上的任意两点 \(i,k\),必有 \(dist_{i,k}+dist_{k,i}<0\)。
因为 \(dist_{i,i}\) 的初值为 \(0\)。所以当外层循环到了 \(k\),\(dist_{i,i}\) 会因为此被更新为负的值(内层的 \(j\) 也可能循环到 \(i\))。
因此当 \(dist_{i,i}<0\),图中有负环。
4. 最短路算法一览表
| 算法名 | Dijstra | Floyd | Spfa | Johnson |
|---|---|---|---|---|
| 最短路类型 | 单源最短路 | 全源最短路 | 单源最短路 | 全源最短路 |
| 适用的图 | 无负权图 | 任意图 | 任意图 | 任意图 |
| 可以判断负环 | 不可以 | 可以 | 可以 | 可以 |
| 时间复杂度 | \(O(m\log m)\) | \(O(n^3)\) | \(O(nm)\) | \(O(nm\log m)\) |
迁移自洛谷

浙公网安备 33010602011771号