5.2.6 Floyd
5.2.6 Floyd
适用条件:多源最短路(求任意两点间的最短距离)、允许存在负权边。
[注]:由于其时间复杂度高达
Floyd 算法与 Dijkstra、SPFA 最大的不同在于,它不是用来求“单源”(从一个固定起点出发)的,而是一次性把地图上任意两个村庄之间的最短路全部算出来。
有个极其贴切的现实模型,即“航班中转(找中间人)”。 假设你要从城市
必备概念
只需要记下一个最核心的数据结构:
dist[N][N]:一个二维数组(邻接矩阵),存储的是目前从点到点 的最短距离。 - 起初,它只记录“直飞”的距离(也就是输入的边)。
- 随着算法运行,它会不断被“中转航班”更新,最终变成全局最短距离。
沙盘推演:
地图情报:城市 1、2、3。直飞航线:1->2 票价 8,2->3 票价 1,1->3 票价 10。
初始状态:
dist[1][2] = 8dist[2][3] = 1dist[1][3] = 10第一步:所有人尝试把城市 1 当作中转站
2 说:“我要去 3,如果去 1 中转……”(毫无意义,绕远了)。没人的票价被更新。
第二步:所有人尝试把城市 2 当作中转站(高潮来了)
1 说:“我要去 3,目前的票价是
dist[1][3] = 10。如果我先去 2,再去 3,票价是dist[1][2] + dist[2][3] = 8 + 1 = 9。”因为
,路线被优化! 更新底牌: dist[1][3] = 9。第三步:所有人尝试把城市 3 当作中转站
也没有人能得到更便宜的票价。
最终收网:
任意两点间的最短距离都已经锁定。
代码解析
初始化
在 Floyd 算法中,初始化非常关键,必须遵守三条原则:
- 自己到自己的距离是 0(
dist[i][i] = 0) - 一开始互相没路的点,距离是无穷大(
inf) - 如果有两点之间有多条边(重边),只记录最短的那条
1
2
3
4
5
6
7
8
9
10
11
12//初始化为无穷大
for(int i = 1;i <= n;++i){
for(int j = 1;j <= n;++j){
if(i == j) dist[i][j] = 0;
else dist[i][j] = INF;
}
}
//读入边,注意重边
for(int i = 1;i <= m;++i){
int u,v,w; cin >> u >> v >> w;
dist[u][v] = min(dist[u][v],w);
}- 自己到自己的距离是 0(
核心循环
Floyd 算法的核心是三层for循环
这一块要记住变量
必须写在最外层循环,因为 Floyd 的本质是动态规划。它指 在只允许经过前 个城市作为中转站的情况下,任意两点的最短距离。如果把 写在内层,就会导致前面还没彻底算清楚的中转方案被提前跳过,答案全错。 1
2
3
4
5
6
7
8
9
10
11for(int k = 1;k <= n;++k){
for(int i = 1;i <= n;++i){ //起点
for(int j = 1;j <= n;++j){ //终点
if(dist[i][k] < INF && dist[k][j] < INF){
if(dist[i][j] > dist[i][k] + dist[k][j]){
dist[i][j] = dist[i][k] + dist[k][j];
}
}
}
}
}
综合代码
1 | const int N = 505; |
例题
1. B3647 【模板】Floyd
Ques
题目描述
给出一张由
求出所有点对
输入格式
第一行为两个整数
接下来
输出格式
输出
第
输入 #1
1 | 4 4 |
输出 #1
1 | 0 1 2 1 |
说明/提示
对于
数据中可能存在重边。
Ans
1 | const int INF = 1e9; |
相关文章
[[5-2-3-Dijkstra]] [[5-2-4-SPFA-Bellman-Ford]] [[5-3-2-MST]]

