You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

76 lines
3.1 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#include <bits/stdc++.h>
using namespace std;
#define x first
#define y second
typedef pair<int, int> PII;
const int N = 160;
const int INF = 0x3f3f3f3f;
PII q[N]; // 每个点的坐标
char g[N][N]; // 邻接矩阵,记录是否中间有边
double dis[N][N]; // 每两个牧区之间的距离
double maxd[N]; // 距离牧区i最远的最短距离是多少
// 欧几里得距离
double get(PII a, PII b) {
int x = a.x - b.x, y = a.y - b.y;
return sqrt(x * x + y * y);
}
int main() {
// 牧区:点,牧场:连通块
int n; // 点数
scanf("%d", &n);
for (int i = 0; i < n; i++) scanf("%d %d", &q[i].x, &q[i].y); // 点坐标
// 邻接矩阵,描述点与点之间的连通关系
// 这个用int还没法读入因为它的输入是连续的中间没有空格讨厌啊~
for (int i = 0; i < n; i++) scanf("%s", g[i]);
// 遍历行与列,计算出每两个点之间的距离
// ① 距离只在同一连通块中存在不同的连通块间的距离是INF
// ② 自己与自己的距离是0
// ③ 两个牧区相连,距离=sqrt((x1-x2)^2+(y1-y2)^2)
// 本质: g + q => dis
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++) {
// 1. double数组在全局变量区默认值是0
// 2. 当i==j时自己到自己的距离是0所以没动作直接使用默认值即d[i][i]=0,自己到自己没有距离
// 3. 当g[i][j]=='1'时,说明两者之间存在一条边,距离就是欧几里得距离计算办法
// 4. 否则就是没有路径
if (i == j)
dis[i][j] = 0;
else if (g[i][j] == '1')
dis[i][j] = get(q[i], q[j]);
else // 注意由于dis数组是一个double类型不能用memset(0x3f)进行初始化正无穷
dis[i][j] = INF;
}
// ① Floyd算法 k,i,j
// 原始各连通块内的多源最短路径
for (int k = 0; k < n; k++)
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);
// ② 未建设两个连通块之间线路前,每个点的最长 最短路径
// maxd[i]:由i出发可以走的最远距离
double res1 = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) // 求i到离i(最短路径) 最长距离
if (dis[i][j] < INF) maxd[i] = max(maxd[i], dis[i][j]);
// 所有点的最远距离PK,可以获取到最大直径
res1 = max(res1, maxd[i]);
}
// ③ 连线操作,更新新牧场直径
double res2 = INF;
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
if (dis[i][j] == INF) // 如果i,j不在同一个连通块内
// 连接原来不在同一连通块中的两个点后,可以取得的最小直径
res2 = min(res2, maxd[i] + maxd[j] + get(q[i], q[j]));
// PK一下
printf("%.6lf\n", max(res1, res2));
return 0;
}