无线网络
无线网络
农夫约翰的农场可以看作一个二维平面。
农场中散布着 头奶牛,每头奶牛的位置坐标已知。
农场中还建有 个 wifi 基站,每个基站的位置坐标已知。
这 个位置坐标两两不同。
第一个基站的有效覆盖范围 和第二个基站的有效覆盖范围 均可由约翰自由设定。
因为奶牛喜欢保持电子邮件联系,所以约翰希望所有奶牛都能被无线网络覆盖。
如果一头奶牛满足以下两个条件中的至少一个:
- 它到第一个基站的距离不超过
- 它到第二个基站的距离不超过
那么就视为它已被无线网络覆盖。
同时为了降低成本,约翰希望 尽可能小。
请你计算 的最小可能值。
输入格式
第一行包含 个整数 ,其中 为奶牛数量, 为第一个基站的坐标, 为第二个基站的坐标。
接下来 行,每行包含两个整数 ,表示一头奶牛的位置坐标 。
输出格式
输出 的最小可能值,答案四舍五入到个位。
数据范围
前 个测试点满足 。
所有测试点满足 ,。
输入样例1:
2 -1 0 5 3 0 2 5 2
输出样例1:
6
输入样例2:
4 0 0 5 0 9 4 8 3 -1 0 1 4
输出样例2:
33
解题思路
题目要求答案保留小数点后位,其实答案一定是一个整数,这是因为所有的点都是整数点,对于其中一个基站,在以它为圆心的圆上(圆弧上)一定会有一头牛(点),如果这个圆上没有点,那么这个圆的半径就一定可以缩小。所以半径一定是两个整数点之间的距离的平方,是一个整数。
一种做法是先枚举每一个点,这个点到两个基站的距离(这里的距离是带平方的,下同)分别是和,接着先选择,即确定第个基站的半径大小,第个基站的半径记为,然后再枚举其他点到第个基站的距离,如果某个点到第个基站的距离大于,那么表示第个基站不可以覆盖到这个点,这时第个基站的半径就是这个点到第个基站的距离与取最大值。枚举完第个基站后,再选择,即确定第个基站的半径大小,再枚举其他的点来确定第个基站的半径大小,与上面的方法相同。
时间复杂度为,AC代码如下:
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 typedef long long LL; 5 6 const int N = 2010; 7 8 LL d1[N], d2[N]; 9 10 int main() { 11 int n, x1, y1, x2, y2; 12 scanf("%d %d %d %d %d", &n, &x1, &y1, &x2, &y2); 13 for (int i = 0; i < n; i++) { 14 int x, y; 15 scanf("%d %d", &x, &y); 16 d1[i] = 1ll * (x1 - x) * (x1 - x) + 1ll * (y1 - y) * (y1 - y); 17 d2[i] = 1ll * (x2 - x) * (x2 - x) + 1ll * (y2 - y) * (y2 - y); 18 } 19 20 LL ret = 9e18; 21 for (int i = 0; i < n; i++) { 22 LL d = 0; // 先确定第1个基站的半径,此时d表示第2个基站的半径 23 for (int j = 0; j < n; j++) { 24 if (i != j && d1[j] > d1[i]) d = max(d, d2[j]); // 第1个基站覆盖不了第j个点,更新d 25 } 26 ret = min(ret, d1[i] + d); 27 28 d = 0; // 然后确定第2个基站的半径,此时d表示第1个基站的半径 29 for (int j = 0; j < n; j++) { 30 if (i != j && d2[j] > d2[i]) d = max(d, d1[j]); // 第2个基站覆盖不了第j个点,更新d 31 } 32 ret = min(ret, d2[i] + d); 33 } 34 35 printf("%lld", ret); 36 37 return 0; 38 }
还有一种思路是,由于圆上一定会有一个点,所以先求每个点到其中一个基站的距离,这里假设到第个基站的距离,所以最多会有种距离。然后枚举这种距离,枚举完一种距离后,有一些点会被第个基站覆盖,剩下的点都是不能被第个基站覆盖的,此时另外一个基站就要把这些点覆盖,即另外一个基站的半径就可以确定下来了,就是这些不能被第个基站覆盖的点中,到第个基站的最大距离。
因此可以先把所有点到第个基站的距离进行降序排序,然后从大到小枚举第个基站的半径。从大到小枚举的好处是,每次都可以让一个点落到第个基站覆盖的范围外,相当于每次都从圆内往外抛出一个点,这个点就需要被第个基站覆盖,相当于在另外一个基站需要覆盖的点集中加一个点,然后用抛出的这个点更新第个基站的半径,就可以知道另外一个基站的最小半径是多少了。因此每枚举完第个基站的半径后,另外一个基站的半径就可以通过的复杂度得到。
如果一个圆上有多个点,那么按照上面的枚举方式这些在同一个圆上的点并不是同时抛出的,而是一个一个依次抛出,但这并不会影响答案,因为将其中一个点抛出时,只会让第个基站的半径增大,并不会影响到之前确定的最小的半径。
时间复杂度为,AC代码如下:
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 typedef long long LL; 5 typedef pair<LL, int> PLI; 6 7 const int N = 2010; 8 9 LL d1[N], d2[N]; 10 PLI p[N]; 11 12 int main() { 13 int n, x1, y1, x2, y2; 14 scanf("%d %d %d %d %d", &n, &x1, &y1, &x2, &y2); 15 for (int i = 0; i < n; i++) { 16 int x, y; 17 scanf("%d %d", &x, &y); 18 d1[i] = 1ll * (x1 - x) * (x1 - x) + 1ll * (y1 - y) * (y1 - y); 19 d2[i] = 1ll * (x2 - x) * (x2 - x) + 1ll * (y2 - y) * (y2 - y); 20 p[i] = {d1[i], i}; 21 } 22 23 sort(p, p + n, greater<PLI>()); 24 25 LL ret = 9e18, d = 0; 26 for (int i = 0; i < n; i++) { 27 ret = min(ret, p[i].first + d); 28 d = max(d, d2[p[i].second]); // 另外一个点的半径就是与被抛出的点i到第2个基站的距离取最大值 29 } 30 31 printf("%lld", min(ret, d)); // 最后表示第1个基站覆盖0个点,第2个基站覆盖所有点,对这种情况再取一个最小值 32 33 return 0; 34 }
参考资料
AcWing 4429. 无线网络(AcWing杯 - 周赛):https://www.acwing.com/video/3931/
本文来自博客园,作者:onlyblues,转载请注明原文链接:https://www.cnblogs.com/onlyblues/p/16344114.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效