POJ3714
题意 N*2个点
前N个一类 后N个一类
问两类间最短距离
方法:判断距离时,如果标记不一致,视为无穷大(inf)
具体讲解参看 http://blog.youkuaiyun.com/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;
}