ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

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

2021-07-03 11:02:37  阅读:186  来源: 互联网

标签:frac int ybt mid zb 圈套 距离 include 金牌


圈套问题

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

题目大意

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

思路

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

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

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

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

但容易想到在最差情况,所有点都在 \(x-a\sim x+a\) 中,那就没差啊。

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

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

所以最多枚举找到的点不会超过 \(6\) 个,所以 \(n^2\) 的复杂度就变成了 \(6n\) 即 \(n\),就可以 \(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;
}

标签:frac,int,ybt,mid,zb,圈套,距离,include,金牌
来源: https://www.cnblogs.com/Sakura-TJH/p/YBT_JPDH_6-1-3.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有