信息
- ID
- 562
- 时间
- 1000ms
- 内存
- 128MiB
- 难度
- 6
- 标签
- (无)
- 递交数
- 66
- 已通过
- 23
- 上传者
难点主要在读题上,要分清楚什么是牧区、什么是牧场、什么是大牧场。
最短路的部分用floyd比较方便快捷。也可以用floyd的答案判断两个点是否相连。
特别需要注意可能会出现直径不经过新加入的边的情况。
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 150;
const double INF = 200000 * 150;
int n, m, s, t;
int x[MAXN + 5], y[MAXN + 5];
double dis[MAXN + 5][MAXN + 5];
double len(int u, int v)
{
return sqrt((long long)(x[u] - x[v]) * (x[u] - x[v]) +
(long long)(y[u] - y[v]) * (y[u] - y[v]));
}
double maxLen[MAXN]; // maxLen[i]: 到i号点距离最远的点的距离
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
// 输入
cin >> n;
for (int i = 1; i <= n; i++)
cin >> x[i] >> y[i];
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
dis[i][j] = INF;
dis[i][i] = 0;
}
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
{
char now;
cin >> now; // 牧区 i 与牧区 j 的连接关系是 now
if (now == '1')
{
dis[i][j] = len(i, j);
}
}
// floyd
for (int k = 1; k <= n; k++)
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
dis[i][j] = min(dis[i][j],
dis[i][k] + dis[k][j]);
// 预处理距离每个点最远的点的距离
for (int i = 1; i <= n; i++)
{
maxLen[i] = 0;
for (int j = 1; j <= n; j++)
{
// double类型直接比较相等可能会有问题
// 下面的式子逻辑上等价于 dis[i][j]!=INF
if (abs(dis[i][j] - INF) > 1e-12)
{
maxLen[i] = max(maxLen[i], dis[i][j]);
}
}
}
// 枚举可能的答案
double ans = INF;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
// 如果 i,j 属于不同的牧场,尝试加一条边沟通两个牧场
if (abs(dis[i][j] - INF) < 1e-12)
{
if (maxLen[i] + maxLen[j] + len(i, j) < ans)
{
ans = maxLen[i] + maxLen[j] + len(i, j);
}
}
}
}
// 有没有可能还不如原来的直径大
for (int i = 1; i <= n; i++)
ans = max(ans, maxLen[i]);
// 输出
cout << fixed << setprecision(6) << ans << "\n";
return 0;
}