题目出处:《[信息学奥赛一本通](C++)版》P472页
本题在书中作为 Floyed 问题,估此处采用 Floyd 解法。Floyed的时间复杂度是O (N3),适用于出现负边权的情况
核心思想是三层循环,
第一层循环中间点 k,
第二层循环起点 i,
第三层循环终点 j,
算法的思想很容易理解:如果点 i 到点 k 的距离加上点 k 到点 j 的距离小于原先点 i 到点 j 的距离,那么就用这个更短的路径长度来更新原先点 i 到点 j 的距离,用代码表示就是
If (res[i][j] >res[i][k] + res[k][j]) res[i][j] = res[i][k] + res[k][j];
注:在初始化时有个小技巧
如果是 int 数组,memset(g, 0x3f, sizeof(g)) 可全部初始化为一个很大的数
如果是 double 数组,memset(g,127,sizeof(g)) 可全部初始化为一个很大的数
题解代码:
#include <bits/stdc++.h>
using namespace std;
int n, m;
int main()
{
scanf("%d", &n);
int x[n + 1], y[n + 1];
double res[n + 1][n + 1];
memset(res, 127, sizeof res); // res初始化为一个很大值
for (int i = 1; i <= n; i ++ )
scanf("%d%d", &x[i], &y[i]);
scanf("%d", &m);
for (int i = 1; i <= m; i ++ )
{
int a1, b1;
scanf("%d%d", &a1, &b1);// 使用距离公式,每次读入时计算距离
res[a1][b1] = res[b1][a1] = sqrt(pow(double(x[a1] - x[b1]), 2) + pow(double(y[a1] - y[b1]), 2));
}
int s, t;
scanf("%d%d", &s, &t);
for (int k = 1; k <= n; k ++ )// Floyd三重循环
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= n; j ++ )
{
if ((i != j) && (i != k) && (k != j))// 如果绕路走更近,就绕路
res[i][j] = min(res[i][j], res[i][k] + res[k][j]);
}
printf("%.02lf\n", res[s][t]);
return 0;
}