POJ 3714 最近点对

POJ3714

题意 N*2个点

前N个一类 后N个一类

问两类间最短距离


方法:判断距离时,如果标记不一致,视为无穷大(inf)

具体讲解参看 http://blog.csdn.net/lonelycatcher/article/details/7973046/

【】

首先对点 作 X 排序

然后对两边分治

两边的 最短 d1 d2 d=min(d1,d2)

我们还需要知道,一个在左,一个在右的情况

因为要最短点对

所以 距离中点超过d的肯定是没用了

那么选出距离中点 d 以内的点们

根据Y排序一次

从下往上刷

垂直距离超过d后,肯定也没用了

且因为 d 是两边最短距离

根据抽屉原理 在一个d*2d的矩形里,点不会超过6个

所以每个点最多会碰见有限个点

这样刷一发 分治就解决了……

【】

早上起来敲了一发,20min,忘记加cmath,本地居然不报错……

CE了两发,一A。

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<cmath>

using namespace std;
#define LL long long
double inf = 1e30;
int T,n;

int useful[200005];
struct node{
	double x;
	double y;
	bool f;
}p[200005];

bool cmpx(node a, node b){
	return a.x < b.x;
}
bool cmpy(int a, int b){
	return p[a].y < p[b].y;
}

double dis(int a,int b){
	if(p[a].f == p[b].f) return inf;
	else
	return sqrt((p[a].x-p[b].x)*(p[a].x-p[b].x)+(p[a].y-p[b].y)*(p[a].y-p[b].y));
}

double search(int l,int r){
	if(l == r){
		return inf;
	}
	if(l == r - 1){
		return dis(l,r);
	}
	else {
		int m = (l+r)/2;
		double d1 = search(l,m);
		double d2 = search(m+1,r);
		double d = std::min(d1,d2);
		double mid = (p[m].x + p[m+1].x)/2.0;
		int k = 1;
		for(int i = l; i <= r; ++i){
			if(fabs(p[i].x-mid)<=d){
				useful[k++] = i;
			}
		}
		k--;
		sort(useful+1,useful+1+k,cmpy);
		for(int i = 1; i <= k; i++){
			for(int j = i+1; j<=k; j++){
				if(fabs(p[useful[i]].y-p[useful[j]].y)>=d)
				break;
				else {
					double nd = dis(useful[i],useful[j]);
					if(nd < d){
						d = nd;
					} 
				}
			}
		}
		return d;
	}
}
int main()
{
	scanf("%d",&T);
	while(T--){
		scanf("%d", &n);
		for(int i = 1; i <= n; i++){
			scanf("%lf%lf",&p[i].x,&p[i].y);
			p[i].f = 1;
		}
		for(int i = n+1; i <= 2*n; i++){
			scanf("%lf%lf",&p[i].x,&p[i].y);
			p[i].f = 0;
		}
		sort(p+1,p+1+n+n,cmpx);
		double ans = search(1,n+n);
		printf("%.3f\n",ans);
	}
	
	return 0;
 } 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值