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.

80 lines
3.6 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;
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;
}