HDU-1007.Quoit Design

33 篇文章 0 订阅
27 篇文章 0 订阅

在这里插入图片描述
地址:http://acm.hdu.edu.cn/showproblem.php?pid=1007
思路:最近点对+分治
对于点集a[n]先按x坐标从小到大排序,取中点a[n/2]将其分成左右两边进行分治,那么最近点对分为三种情况:
1.最近点对都在左边 resL;
2.最近点对都在右边 resR;
3.最近点对一个在左边,一个在右边 resH。
那么答案res为三种情况中的最小值,前两种情况按照分治思想可以处理,主要是第三种情况的处理。
首先分治求出 res=min(resL,resR),对于resH,可以遍历左边点集的点去找右边点集的最近点对,有已知现在最小的最近点对值res,因此对于左边点集的点aLi,比res小的其右边点集的最近点对只可能在一个 (2res) X res的矩形内
在这里插入图片描述
由于虚线分成的6个矩形的对角线长度为 5 6 r e s \frac{5}{6}res 65res ,若该矩形内有两个点,那么其距离就小于res,而res本就是左右两边最近点对距离的最小值,因此与res矛盾,故 (2
res) X res的矩形内最多只有6个点
因此可以对右边点集 x<a[n/2]+res的点按y坐标轴从小到大排序,然后遍历左边点集aLi,在 aLi.y-res到 aLi.y+res的范围内找即可

Code:

#include<iostream>
#include<algorithm>
using namespace std;
typedef pair<double,double> pr;

const int MAX_N=1e5+5;
int n;
pr a[MAX_N];

bool cmp(const pr &A,const pr &B){
	if(A.second==B.second)	return A.first<B.first;
	return A.second<B.second;
}

double Find(int l,int r){
	if(l==r)	return 1e16;
	int h=(l+r)/2,ri,k;
	double res=min(Find(l,h),Find(h+1,r));
	ri=lower_bound(a+h+1,a+r+1,pr{a[h].first+res+0.01,0})-a;
	sort(a+h+1,a+ri,cmp);
	if(ri==n)	--ri;
	for(int i=l;i<=h;++i)
	{
		k=lower_bound(a+h+1,a+ri,pr{0,a[i].second-res-0.01},cmp)-a;
		while(k<=ri&&a[i].second+res>=a[k].second){
			res=min(res,sqrt(pow(a[i].first-a[k].first,2)+pow(a[i].second-a[k].second,2)));
			++k;
		}
	}
	return res;
}

int main()
{
	while(scanf("%d",&n)&&n){
		for(int i=0;i<n;++i)
			scanf("%lf%lf",&a[i].first,&a[i].second);
		sort(a,a+n);
		printf("%.2lf\n",Find(0,n-1)/2);
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值