多源最短路
1040 字
5 分钟
多源最短路
Floyd 算法
算法概述
Floyd算法是一种多源最短路径算法,用于求解图中任意两个节点之间的最短路径。该算法基于动态规划,通过不断在路径中插入中间节点来更新最短路径,因此也被称为插点法。
适用条件
· 适用于任何图(有向图、无向图、带权图) · 要求不存在负环(但可以处理负权边) · 最短路必须存在
核心思想
状态定义
设 f[k][i][j] 表示经过编号不超过 k 的节点,从节点 i 到节点 j 的最短路径长度。
状态转移方程
对于每个中间节点 k,考虑两种情况:
1. 不经过节点 k:f[k][i][j] = f[k-1][i][j]
2. 经过节点 k:f[k][i][j] = f[k-1][i][k] + f[k-1][k][j]
取两者最小值:f[k][i][j] = min(f[k-1][i][j], f[k-1][i][k] + f[k-1][k][j]空间优化
实际实现中省略第一维,使用二维数组迭代更新
f[i][j] = min(f[i][j], f[i][k] + f[k][j])代码实现
#include <iostream>#include <cstring>#include <algorithm>using namespace std;
const int N = 210; // 根据题目调整大小const int INF = 0x3f3f3f3f;int f[N][N];int n, m;
int main() { cin >> n >> m;
// 初始化 memset(f, 0x3f, sizeof f); for (int i = 1; i <= n; i++) { f[i][i] = 0; // 自己到自己的距离为0 }
// 读入边 for (int i = 1; i <= m; i++) { int a, b, c; cin >> a >> b >> c; f[a][b] = f[b][a] = min(f[a][b], c); // 处理重边,选择最小边 }
// Floyd算法核心 for (int k = 1; k <= n; k++) { for (int i = 1; i <= n; i++) { for (int j = 1; j <= n; j++) { if (f[i][k] != INF && f[k][j] != INF) { // 防止溢出 f[i][j] = min(f[i][j], f[i][k] + f[k][j]); } } } }
// 输出结果 for (int i = 1; i <= n; i++) { for (int j = 1; j <= n; j++) { if (f[i][j] == INF) { cout << "INF "; } else { cout << f[i][j] << " "; } } cout << endl; }
return 0;}三维
#include <iostream>#include <cstring>#include <algorithm>using namespace std;
const int N = 210; // 根据题目调整大小const int INF = 0x3f3f3f3f;int f[N][N][N];int n, m;
int main() { cin >> n >> m;
// 初始化 memset(f, 0x3f, sizeof f);
// 初始化k=0的情况(不经过任何中间点) for (int i = 1; i <= n; i++) { for (int j = 1; j <= n; j++) { if (i == j) { f[0][i][j] = 0; // 自己到自己的距离为0 } } }
// 读入边(初始化k=0的直接路径) for (int i = 1; i <= m; i++) { int a, b, c; cin >> a >> b >> c; f[0][a][b] = min(f[0][a][b], c); // 处理重边 f[0][b][a] = min(f[0][b][a], c); // 无向图 }
// Floyd算法核心(三维版本) for (int k = 1; k <= n; k++) { for (int i = 1; i <= n; i++) { for (int j = 1; j <= n; j++) { // 状态转移:经过前k个点 = min(经过前k-1个点, 经过第k个点) if (f[k-1][i][k] != INF && f[k-1][k][j] != INF) { f[k][i][j] = min(f[k-1][i][j], f[k-1][i][k] + f[k-1][k][j]); } else { f[k][i][j] = f[k-1][i][j]; } } } }
// 输出结果(使用经过所有n个点的结果) for (int i = 1; i <= n; i++) { for (int j = 1; j <= n; j++) { if (f[n][i][j] == INF) { cout << "INF "; } else { cout << f[n][i][j] << " "; } } cout << endl; }
return 0;}时空复杂度
时间复杂度 · O(n³),其中 n 为节点数 · 三重循环:k → i → j
空间复杂度 · O(n²),使用二维数组存储距离矩阵
通过数学归纳法证明算法正确性:
· 基础:k=0时,f[i][j]为直接边权值 · 归纳:假设已知前k-1个节点时的最短路径,加入第k个节点时,要么不经过k,要么经过k
注意事项
- 初始化要点: · 对角线元素初始化为0 · 有边连接的点初始化为边权值 · 无边连接的点初始化为无穷大
- 重边处理:
f[a][b] = min(f[a][b], c); // 取最小边权
- 负权边处理: · 可以处理负权边 · 但不能处理负环(会陷入无限循环)
- 无穷大判断:
if (f[i][k] != INF && f[k][j] != INF) {// 防止整数溢出}
应用场景
- 任意两点间最短路径问题
- 传递闭包计算
- 最小环检测
- 图的连通性判断
文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!
相关文章智能推荐
1
单源最短路
算法每次从未确定最短路径的点中,选择距离起点最近的点,标记它的最短路径,并用它来更新邻居节点的距离。
2
线性DP
算法线性DP:状态转移只依赖于前一个或前几个状态,状态之间的关系是线性的,通常可以用一维或二维数组存储状态。 三个关键要素
3
区间DP
算法定义 区间DP是用区间的左右端点来描述状态,通过小区间的解来推导出大区间的解的动态规划方法
4
背包问题
算法问题:每个物品选一次,总价值最大且不超过容量 v[]:代表体积 w[]:代表价值
5
动态规划
算法定义: 动态规划(DP):解决多阶段决策问题的算法思想。将复杂问题分解为更小的子问题,并存储子问题的解(状态),从而避免重复计算,提高效率。
随机文章随机推荐

