关于c++的FLOYD算法 P2910 [USACO08OPEN] Clear And Present Danger S 题解
算法原理:
Floyd算法用于求解图中所有顶点对之间的最短路径,基于动态规划思想,通过逐步优化中间节点实现。其核心递推公式为:
其中 表示从i到j且仅经过前k个节点的最短路径。
例题:P2910 [USACO08OPEN] Clear And Present Danger S
题目描述
农夫约翰正驾驶一条小艇在牛勒比海上航行.
海上有 N(1≤N≤100) 个岛屿,用 1 到 N 编号.约翰从 1 号小岛出发,最后到达 N 号小岛.
一张藏宝图上说,如果他的路程上经过的小岛依次出现了 A1,A2,…,AM(2≤M≤10000) 这样的序列(不一定相邻),那他最终就能找到古老的宝藏. 但是,由于牛勒比海有海盗出没.约翰知道任意两个岛屿之间的航线上海盗出没的概率,他用一个危险指数 Di,j(0≤Di,j≤100000) 来描述.他希望他的寻宝活动经过的航线危险指数之和最小.那么,在找到宝藏的前提下,这个最小的危险指数是多少呢?
输入格式
第一行:两个用空格隔开的正整数 N 和 M。
第二到第 M+1 行:第 i+1 行用一个整数 Ai 表示 FJ 必须经过的第 i 个岛屿
第 M+2 到第 N+M+1 行:第 i+M+1 行包含 N 个用空格隔开的非负整数分别表示 i 号小岛到第 1…N 号小岛的航线各自的危险指数。保证第 i 个数是 0。
输出格式
第一行:FJ 在找到宝藏的前提下经过的航线的危险指数之和的最小值。
说明 这组数据中有三个岛屿,藏宝图要求 FJ 按顺序经过四个岛屿:1 号岛屿、2 号岛屿、回到 1 号岛屿、最后到 3 号岛屿。每条航线的危险指数也给出了:航路(1,2),(2,3),(3,1) 和它们的反向路径的危险指数分别是 5,2,1。
FJ 可以通过依次经过 1,3,2,3,1,3 号岛屿以 7 的最小总危险指数获得宝藏。这条道路满足了奶牛地图的要求 (1,2,1,3)。我们避开了 1 号和 2 号岛屿之间的航线,因为它的危险指数太大了。
注意:测试数据中 a 到 b 的危险指数不一定等于 b 到 a 的危险指数!
输入输出样例
输入
3 4
1
2
1
3
0 5 1
5 0 2
1 2 0
输出
7
代码:
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int MAXN = 105;
int n, m, ans;
int dist[MAXN][MAXN];
int order[10010];
signed main() {
cin >> n >> m;
for(int i = 1; i <= m; i++) cin >> order[i];
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
cin >> dist[i][j];
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]);
for(int i = 2; i <= m; i++) ans += dist[order[i - 1]][order[i]];
ans += dist[1][order[1]];
ans += dist[order[m]][n];
cout << ans;
return 0;
}
以下是代码的详细分步解析:
-
定义
const int MAXN = 105; int n, m, ans; int dist[MAXN][MAXN]; // 存储最短路径的邻接矩阵 int order[10010]; // 存储订单访问顺序
MAXN=
表示图中最多有个节点
order
数组规模10010说明最多支持10000个订单(从i=1
到i=m
)
-
主函数
步骤1:初始化邻接矩阵
for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++) cin >> dist[i][j];
- 输入
n×n
的邻接矩阵,dist[i][j]
表示节点i到j的直接距离
步骤2:Floyd-Warshall算法
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]);
- 通过动态规划计算所有节点对的最短路径
- 时间复杂度
,有n≤100的规模,可行
步骤3:路径计算
// 累加订单节点间的路径 for(int i = 2; i <= m; i++) ans += dist[order[i - 1]][order[i]]; // 添加起点和终点 ans += dist[1][order[1]]; // 从节点1到第一个订单节点 ans += dist[order[m]][n]; // 从最后一个订单节点到节点n
- 总路径构成:1→order[1]→⋯→order[m]→n
- 输入
算法复杂度分析算法复杂度分析:
- 时间复杂度:由Floyd-Warshall算法主导,为
- 空间复杂度:
(邻接矩阵存储)
示例:
输入
3 2
2 3
0 2 3
2 0 1
3 1 0
- Floyd计算后得到全源最短路径矩阵
- 路径计算:dist[1→2]+dist[2→3]+dist[3→3]=2+1+0=3
(注意:实际场景中dist[3→3]
应为0)