弗洛伊德算法
食用指南:
对该算法程序编写以及踩坑点很熟悉的同学可以直接跳转到代码模板查看完整代码
只有基础算法的题目会有关于该算法的原理,实现步骤,代码注意点,代码模板,代码误区的讲解
非基础算法的题目侧重题目分析,代码实现,以及必要的代码理解误区
5大最短路一图总结:
题目描述:
-
给定一个 n 个点 m 条边的有向图,图中可能存在重边和自环,边权可能为负数。
再给定 k 个询问,每个询问包含两个整数 x 和 y,表示查询从点 x 到点 y 的最短距离,如果路径不存在,则输出 impossible。
数据保证图中不存在负权回路。输入格式
第一行包含三个整数 n,m,k。
接下来 m 行,每行包含三个整数 x,y,z,表示存在一条从点 x 到点 y 的有向边,边长为 z。
接下来 k 行,每行包含两个整数 x,y,表示询问点 x 到点 y 的最短距离。输出格式
共 k 行,每行输出一个整数,表示询问的结 果,若询问两点间不存在路径,则输出 impossible。数据范围
1≤n≤200,
1≤k≤n2
1≤m≤20000,
图中涉及边长绝对值均不超过 10000。输入样例:
3 3 2
1 2 1
2 3 2
1 3 1
2 1
1 3
输出样例:
impossible
1 -
题目来源:https://www.acwing.com/problem/content/description/856/
题目分析:
- 有向图 -> 稠密图 -> 邻接矩阵
- 负边权 & 无负环
- 多次询问不同x到y的最短路径:多源最短路径->唯一算法Floyd
- 下面我们总结一下4大单源最短路径算法
顺便讲讲非常简单的O(n3)的Floyd算法
算法原理:
模板算法:
- 传送门:朴素Dijkstra
- 传送门:堆优化Dijkstra
- 传送门:bellman-ford
- 传送门:朴素SPFA
- 传送门:负环SPFA
Floyd:
1. 本质:
- 动态规划,dynamic programming
2. 存储形式:
-
邻接矩阵
不论稀疏图OR稠密图,都采用邻接矩阵
一者存储形式不影响Floyd的步骤和复杂度
二者邻接矩阵便于索引x y之间的距离 -
arr[x][y] = z;
表示x到y的最短距离为z
3. 初始化:
- 开始未存储边,则任意两点之间不连通
- 所以arr[N][N]都存储为无穷远,0x3f3f3f3f
- 除了一个点到自己本身的距离arr[x][x] = 0;
4. 三大步骤:
- 枚举中间点k
- 枚举起点i
- 枚举终点j
- 若借助经过中间点可以缩短起点终点距离,
则更新arr[i][j] = arr[i][k] + arr[k][j];
- 对,三层for循环 外加一个 公式,就是Floyd算法的全部内容
- 时间复杂度:严格O(n3),毕竟三层循环每层都枚举n个图中节点
代码实现:
#include <iostream>
using namespace std;
const int N = 210;
const int INF = 1e9;
int n, m, k;
int d[N][N];
void init(){
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
if(i == j) d[i][j] = 0;
else d[i][j] = INF;
}
void floyd() {
for(int k = 1; k <= n; k++)
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
}
int main() {
cin >> n >> m >> k;
init();
while(m--) {
int x, y, z;
cin >> x >> y >> z;
d[x][y] = min(d[x][y], z); //重边取最短
}
floyd();
while(k--) {
int x, y;
cin >> x >> y;
if(d[x][y] > INF/2) puts("impossible");
else cout << d[x][y] << endl;
}
return 0;
}
代码误区:
1. 三层循环的顺序可以改变吗?
- 不可以,第一层必须是中介点k
- 第二层和第三层可以交换顺序
- 若中介点不在最外层,x y之间的距离确实缩短过,但是不保证是最短
2. Floyd是多源最短路径的唯一算法
- 但是,他也怕负环,当然最短路出题也不可能给个负环
- 除非单独考SPFA + count[N]来确定图中/路径中是否含有负环
本篇感想:
- Floyd算法也就两句话:
- 三层循环,外层中介。
- arr[i][j] = min(arr[i][j], arr[i][k]+arr[k][j]);
- 所以弗洛伊德算法也叫3f算法
- 看完本篇博客,恭喜已登 《筑基境-中期》
距离登仙境不远了,加油