Files
python/TangDou/AcWing_TiGao/T3/Floyd/1125.cpp
HuangHai 1f397eca87 'commit'
2025-08-30 18:35:01 +08:00

80 lines
3.6 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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;
}