AcWing 1145. 北极通讯网络
. 北极通讯网络
一、题目描述
北极的某区域共有 座村庄,每座村庄的坐标用一对整数 表示。
为了加强联系,决定在村庄之间建立通讯网络,使每两座村庄之间都可以 直接 或 间接 通讯。
通讯工具可以是无线电收发机,也可以是卫星设备。
无线电收发机有多种不同型号,不同型号的无线电收发机有一个不同的参数 ,两座村庄之间的距离如果不超过 ,就可以用该型号的无线电收发机直接通讯, 值越大的型号价格越贵。现在要先选择某一种型号的无线电收发机,然后统一给所有村庄配备,数量不限,但型号都是 相同的。
配备卫星设备的两座村庄 无论相距多远都可以直接通讯,但卫星设备是 有限 的,只能给一部分村庄配备。
现在有 台卫星设备,请你编一个程序,计算出应该如何分配这 台卫星设备,才能使所配备的无线电收发机的 值最小。
例如,对于下面三座村庄:
其中,。
如果没有任何卫星设备或只有 台卫星设备 ( 或 ),则满足条件的最小的 ,因为 和 , 和 可以用无线电直接通讯;而 和 可以用 中转实现间接通讯 (即消息从 传到 ,再从 传到 );
如果有 台卫星设备 (),则可以把这两台设备分别分配给 和 ,这样最小的 可取 ,因为 和 之间可以用无线电直接通讯; 和 之间可以用卫星直接通讯; 和 可以用 中转实现间接通讯。
如果有 台卫星设备,则 两两之间都可以直接用卫星通讯,最小的 可取 。
输入格式
第一行为由空格隔开的两个整数 ;
接下来 行,每行两个整数,第 行的 表示第 座村庄的坐标 ()。
输出格式
一个实数,表示最小的 值,结果保留 位小数。
数据范围
输入样例:
3 2
10 10
10 0
30 0
输出样例:
10.00
二、算法
-
假设已经确定了参数的大小, 那么所有两个 距离的村庄 就可以建立联系, 在图中建立了若干连通块
-
参数的大小 与 联通块的数量 成反比:
- 当, 所有村庄间通过卫星相连,共有个连通块
- 当 (:图中村庄之间的距离), 所有顶点连通, 共有个连通块
而题目的要求是: 找到满足连通块个数不超过个的最小的
本质上就是对算法的 魔改 ,考虑的计算过程:
按照边权递增的顺序, 当把两个不连通的顶点连通时, 相当于在图中减少了一个连通块, 在连通块恰好减少到时, 对应的边权因为有递增的保证, 所以是满足条件的最小边权。
#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> PII;
#define x first
#define y second
const int N = 510, M = N * N / 2; // C(n,2)
int n, k;
struct Edge {
int a, b;
double c;
const bool operator<(const Edge &t) const {
return c < t.c;
}
} edge[M];
int el;
// 每个村庄的坐标
PII q[M];
// 欧几里得距离
double get_dist(PII a, PII b) {
int x = a.x - b.x, y = a.y - b.y;
return sqrt(x * x + y * y);
}
// 并查集
int p[N];
int find(int x) {
if (p[x] != x) p[x] = find(p[x]);
return p[x];
}
int main() {
cin >> n >> k; // n座村庄,有k台卫星设备
for (int i = 0; i < n; i++) cin >> q[i].x >> q[i].y; // 村庄坐标
// 枚举所有点与点之间的边
for (int i = 0; i < n; i++)
for (int j = i + 1; j < n; j++)
edge[el++] = {i, j, get_dist(q[i], q[j])}; // 因为是一个无向图,所以我们取一半就可以了
// 之所以取一半,其实也是为了配合后面的 cnt--,因为cnt--的现实含义是两个点连接上了,家族数量减少了1个
// 如果这里不是取一半,那么后面就需要cnt-=2, 哈哈,就问你是不是懵~
// 边权由小到大排序
sort(edge, edge + el);
// 并查集初始化
for (int i = 0; i < n; i++) p[i] = i;
int cnt = n; // 剩余的连通块数量
double res = 0;
// 原则:长的用卫星,短的用无线电收发机
// 合并完之后,正好剩下k个连通块,停止,每个连通块上安装卫星即可全面通讯
// 给原图的节点中n - k个节点生成一棵最小生成树
for (int i = 0; i < el; i++) { // 枚举每条边
if (cnt == k) break; // 剩余点数为k时停止, 在这k个点上建立卫星站
int a = edge[i].a, b = edge[i].b;
double c = edge[i].c;
a = find(a), b = find(b);
if (a != b) {
p[a] = b;
res = c; // 不停的记录参数d的上限
cnt--; // 连通块数量-1
}
}
printf("%.2lf\n", res);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
2020-03-25 Zabbix Agent for Linux部署
2018-03-25 对于ElasticSearch与Hadoop是如何互相调用的?
2013-03-25 我们在运营前还需要准备的技术储备