原理
问题目标:求解两个城市之间的最短路径。若路径不存在,输出 No path。
核心算法:
- Floyd-Warshall 算法:用于计算图中所有节点对的最短路径。
- 邻接矩阵:存储无向图的边权值,支持快速更新最短路径。
- 动态规划:通过中间节点逐步优化路径长度。
步骤
- 输入处理:读取城市数
n、道路数m,以及每条道路的信息。 - 邻接矩阵初始化:对角线为
0(自身到自身),其余为无穷大(INF)。 - 填充邻接矩阵:遍历所有道路,更新对称边权值。
- Floyd-Warshall 核心逻辑:
- 三重循环遍历所有可能的中间节点
k,起点i,终点j。 - 若
i→k和k→j存在路径,则尝试更新i→j的最短路径。
- 三重循环遍历所有可能的中间节点
- 输出结果:若
A→B的最短路径仍为INF,输出No path,否则输出路径长度。
图示法表示步骤(示例:n=3, m=2, 道路:(1-2, 3), (2-3, 4), A=1, B=3)
- 初始邻接矩阵:
G = [ [0, INF, INF], [INF, 0, INF], [INF, INF, 0] ] - 填充边权值:
G[1][2] = G[2][1] = 3G[2][3] = G[3][2] = 4
- Floyd 迭代(k=2):
G[1][3] = min(INF, G[1][2]+G[2][3] = 3+4=7)→7
- 结果:
1→3的最短路径为7。
代码关键行注释
int shortest(int n, int m, City city[], int A, int B) {
vector<vector<int>> G(n+1, vector<int>(n+1, INF));
for (int i = 1; i <= n; ++i) G[i][i] = 0; // 初始化邻接矩阵
for (int i = 0; i < m; ++i) {
// 无向图双向更新
if (city[i].val < G[city[i].a][city[i].b]) {
G[city[i].a][city[i].b] = city[i].val;
G[city[i].b][city[i].a] = city[i].val;
}
}
// Floyd-Warshall 核心逻辑
for (int k = 1; k <= n; ++k) {
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; ++j) {
// 检查 i→k 和 k→i 是否连通(冗余但无害)
if (G[i][k] != INF && G[k][i] != INF) {
// 动态规划更新最短路径
G[i][j] = min(G[i][j], G[i][k] + G[k][j]);
}
}
}
}
return (G[A][B] == INF) ? -1 : G[A][B]; // 处理不可达情况
}
完整代码程序
#include <cstdint>
#include <iostream>
#include <vector>
#include <climits>
using namespace std;
typedef struct {
int a;
int b;
int val;
} City;
const int INF = INT_MAX / 2;
int shortest(int n, int m, City city[], int A, int B) {
vector<vector<int>> G(n + 1, vector<int>(n + 1, INF));
for (int i = 1; i <= n; ++i) G[i][i] = 0;
for (int i = 0; i < m; ++i) {
if (city[i].val < G[city[i].a][city[i].b]) {
G[city[i].a][city[i].b] = city[i].val;
G[city[i].b][city[i].a] = city[i].val;
}
}
vector<vector<int>> path(n + 1, vector<int>(n + 1, -1));
for (int k = 1; k <= n; ++k) {
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; ++j) {
if (G[i][k] != INF && G[k][i] != INF) {
G[i][j] = min(G[i][j], G[i][k] + G[k][j]);
}
}
}
}
return (G[A][B] == INF) ? -1 : G[A][B];
}
int main() {
int n, m;
while (cin >> n >> m) {
City city[46];
for (int i = 0; i < m; ++i) {
cin >> city[i].a >> city[i].b >> city[i].val;
}
int A, B;
cin >> A >> B;
int res = shortest(n, m, city, A, B);
if (res == -1) cout << "No path" << endl;
else cout << res << endl;
}
return 0;
}
时间复杂度
- 时间复杂度:
- 邻接矩阵初始化:O(n²)。
- 填充边权值:O(m)。
- Floyd-Warshall 算法:**O(n³)**(三重循环)。
- 空间复杂度:
- 邻接矩阵存储:O(n²)。
总结
- 代码特点:
- 使用邻接矩阵和 Floyd-Warshall 算法,确保所有节点对的最短路径计算。
- 处理无向图时双向更新边权值。
- 潜在问题:
City数组大小固定为46,若m > 45会导致数组越界(需确保题目约束)。- 冗余条件
G[i][k] != INF && G[k][i] != INF在无向图中等效于G[i][k] != INF。
- 改进方向:
- 动态调整
City数组大小(如vector<City>)。 - 移除冗余条件,直接使用
G[i][k] + G[k][j]进行更新。
- 动态调整

1365

被折叠的 条评论
为什么被折叠?



