1 条题解
-
0
思路与算法
对每条无向边,用两点坐标差的平方和开平方计算长度。距离矩阵对角为0、无边为无穷,随后运行Floyd:依次允许每个点作为中间点,d[i][j]=min(d[i][j],d[i][k]+d[k][j])。最后输出s到t距离,不能到达时输出-1.00。
正确性说明
初始化矩阵恰表示不经过中间点的路径。处理第k个中间点时,最短路径要么不经过k,要么可拆为i到k与k到j两段;两段的其他中间点都已被允许。由k归纳,完成后覆盖所有可能路径。边长非负,零长度连线与同点起终点也正确。
复杂度
初始化O(n²),读边O(m),Floyd O(n³);总时间O(n³+m),空间O(n²)。用long double保存距离,以两位输出并按声明容差判定。
易错点
无向边须同时赋值两个方向。同坐标不代表没有边,长度可为0;不能用0来表示本题距离矩阵的无边。无路输出-1.00,数值必须有限并保留两位。
参考代码(C++11)
#include <bits/stdc++.h> using namespace std; int main() { int n; cin >> n; vector<int> x(n), y(n); for (int i = 0; i < n; ++i) cin >> x[i] >> y[i]; vector<vector<long double>> d(n, vector<long double>(n, 1e30L)); for (int i = 0; i < n; ++i) d[i][i] = 0; int m; cin >> m; while (m--) { int u, v; cin >> u >> v; --u; --v; long double a = x[u] - x[v], b = y[u] - y[v]; d[u][v] = d[v][u] = sqrtl(a * a + b * b); } int s, t; cin >> s >> t; --s; --t; for (int k = 0; k < n; ++k) for (int i = 0; i < n; ++i) for (int j = 0; j < n; ++j) d[i][j] = min(d[i][j], d[i][k] + d[k][j]); if (d[s][t] > 1e29L) cout << "-1.00\n"; else cout << fixed << setprecision(2) << d[s][t] << "\n"; }
- 1