|
|
#include <bits/stdc++.h>
|
|
|
using namespace std;
|
|
|
|
|
|
typedef pair<int, int> PII;
|
|
|
#define x first
|
|
|
#define y second
|
|
|
|
|
|
const int N = 160;
|
|
|
const int INF = 0x3f3f3f3f;
|
|
|
PII q[N]; // 每个点的坐标
|
|
|
char g[N][N]; // 邻接矩阵,记录是否中间有边
|
|
|
double dis[N][N]; // 每两个牧区(点)之间的距离
|
|
|
double maxd[N]; // maxd[i]:由i点出发,可以到达的最远的最短距离是多少
|
|
|
// Q:什么是最远的最短距离?
|
|
|
// 答:举个不太恰当的例子,比如A->B->C->D,边权都是1 ,同时存在一条A->D,边权是1。此时,有短的不取长的,所以A->D的距离是1,不是3。
|
|
|
|
|
|
// 欧几里得距离
|
|
|
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还没法读入,因为它的输入是连续的,中间没有空格,讨厌啊~
|
|
|
// 字符数组与scanf("%s",g[i])相结合,直接写入二维数组g的每一行上,这个技巧是值得我们学习的。
|
|
|
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]);
|
|
|
|
|
|
// ② (1)求出未建设两个连通块之间线路前,所有连通块的直径最大值res1
|
|
|
// (2)求出未建设两个连通块之间线路前,每个点的可以到达的最远最短距离,下一步做模拟连线时会用到
|
|
|
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;
|
|
|
} |