【ybt金牌导航6-1-3】圈套问题

圈套问题

题目链接:ybt金牌导航6-1-3

题目大意

平面上有 n 个点,你要用 n 个大小相同的圆把点都套进去,且满足圆不相交,求圆最大半径。

思路

其实题目的意思就是要你找平面上距离最近的两个点的距离除二。

你看这个题目,你发现它可以分治法:它可以变成小规模问题,而且规模小了好解决。
那我们就想它能不能合并小规模问题。

那你想,你当然是把 x 轴排序,然后左右分一半的点继续搞。
那如果只剩一个点,最小长度就是 INF。
那接着如何合并,就是处理左右两边相互配对的。

直接两边暴力枚举显然不行,我们考虑一个东西,就是根据两边得出的答案来搞。
那如果那左边答案是 a1,右边是 a2,你中间如果要有答案,就要找到距离小于 a=min{a1,a2} 的。
那首先根据这个,x 轴之间距离总不能大于它把,那我们就把要匹配的点缩小了,就只用找 x 坐标在 xax+a 之间的点互相匹配。

但容易想到在最差情况,所有点都在 xax+a 中,那就没差啊。

那你就再加上 y 轴也不能大于它,把前面选出来满足 x 轴的按 y 轴排序,然后依次枚举,要配对就只跟 y 轴比它大不超过 a 的。
那有人又会想,那如果所有点都跟它不超过呢?
但其实还有一个条件,在你划分出来的左边和右边,点之间的距离都不小于 a
那你就想一边可以跟另一边匹配啊,但在另一边,点之间也有距离,那最多能匹配多少个点呢?

根据鸽笼原理可以知道最多只有 6 个,这里证明:
在这里插入图片描述
对于左边的一个点 P,能跟它配对长度小于 a 只可能在这个区间。
那你就是要让这个区间放尽可能多的点使得任意两个点之间距离不小于 a
接着就是鸽笼原理。
在这里插入图片描述
我们把它分成这样六份。
那我们考虑在里面每个放一个,就是六个,这样是可以实现每个之间距离不小于 a 的。
那你如果要再放一个,就必然会有至少两个点在同一份里面。
那同一份里面如果要距离最长,就是对角线,长度是 a2×a2+2a3×2a3=5a6<a,那就还是小于 a,就不行,所以就不能放超过六个点。

所以最多枚举找到的点不会超过 6 个,所以 n2 的复杂度就变成了 6nn,就可以 nlogn 过本题了。

代码

#include<cmath> #include<cstdio> #include<iostream> #include<algorithm> #define INF 2000000000.0 using namespace std; struct zb { double x, y; }a[100001], tmp[100001]; int n, tn; double dis(zb x, zb y) { return sqrt((x.x - y.x) * (x.x - y.x) + (x.y - y.y) * (x.y - y.y)); } bool cmpx(zb x, zb y) { return x.x < y.x; } bool cmpy(zb x, zb y) { return x.y < y.y; } double slove(int l, int r) { double re; if (l == r) return INF; int mid = (l + r) >> 1; re = min(slove(l, mid), slove(mid + 1, r)); tn = 0;//找在 x 轴不超过范围的 for (int i = mid; i >= l && a[mid].x - a[i].x < re; i--) tmp[++tn] = a[i]; for (int i = mid + 1; i <= r && a[i].x - a[mid].x < re; i++) tmp[++tn] = a[i]; sort(tmp + 1, tmp + tn + 1, cmpy);//把找到的按 y 轴排序 for (int i = 1; i <= tn; i++)//把 y 轴相差不超过范围的丢出来配对 for (int j = i + 1; j <= tn && tmp[j].y - tmp[i].y < re; j++) re = min(re, dis(tmp[i], tmp[j])); return re; } int main() { scanf("%d", &n); while (n) { for (int i = 1; i <= n; i++) scanf("%lf %lf", &a[i].x, &a[i].y); sort(a + 1, a + n + 1, cmpx); printf("%.2lf\n", slove(1, n) / 2);//记得除以 2 scanf("%d", &n); } return 0; }

__EOF__

本文作者あおいSakura
本文链接https://www.cnblogs.com/Sakura-TJH/p/YBT_JPDH_6-1-3.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   あおいSakura  阅读(43)  评论(0编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示