题目链接:poj 3714
题意:给个n,首先个n个点的位置,再给n个人的位置,问你,人到点最短距离是多少?
参考博客:http://yzmduncan.iteye.com/blog/1432880
https://www.cnblogs.com/captain1/p/9607559.html
题解:
感觉看了这两篇博客,都不需要过多的补充,前人栽的树已经很凉了,但我还是要解释下为什么跟鸽巢原理产生了微妙的联系,为什么?因为博主没解释。首先,我先假设你们都看过这两篇博客,因为照搬进来就没多大意思了。
第二篇博客中有段话:对于C1中的每一个点k,能与之配对更新最短距离的,一定是C2中一个长为dis,高为2*dis的一个矩形之内的点。再者,因为S2中每两个点的距离必须>=dis,所以这个矩形之内最多只可能有6个点。
就是这段话,这结论写的真~有~水~平,一点由来也不说,反正我刚看是不明白为什么最多有6个点,当然可能有人没遇到这个疑问,可以略过不看。
然后细想一下,确实是这样的,我们想下,在这个dis*2dis的矩形中,我们要想每两个点的距离都大于等于dis,那么我们最多放4个点在四个不起眼的角落夹缝生存以及放2个点在两条高的中间,如图所示:
看图就清楚了,结论就容易出来了,在矩形中,要满足每两个点必须大于等于dis,
最多放6个点,在放多一个就不满足了。
这个我们就把它说成是鸽巢定理了。
就差不多是那样了,有“最多”,“至少” 这些字眼。
代码:
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long LL;
const int maxn=200010;
#define INF 0x3f3f3f3f
struct point{
double x,y;
int id;
}node[maxn];
int temp[maxn];
bool cmpxy(point a,point b){
if(a.x-b.x!=1e-8) return a.x<b.x;
else return a.y<b.y;
}
bool cmpy(int a,int b){
return node[a].y<node[b].y;
}
double dist(int a,int b){
if(node[a].id!=node[b].id)
return sqrt((node[a].x-node[b].x)*(node[a].x-node[b].x)+(node[a].y-node[b].y)*(node[a].y-node[b].y));
else return INF;
}
double solve(int left,int right) ///分治
{
double d=INF;
if(left==right) return d;
if(left+1==right) return dist(left,right);
int mid=(left+right)/2;
double d1=solve(left,mid);
double d2=solve(mid+1,right);
if(d1<d2) d=d1;
else d=d2;
int k=0;
for(int i=left;i<=right;i++)
if(fabs(node[mid].x-node[i].x)-d<=1e-8)
temp[++k]=i;
sort(temp+1,temp+k+1,cmpy); ///排序,按y
for(int i=1;i<=k;i++)
{
for(int j=i+1;j<=k;j++){
if(fabs(node[temp[j]].y-node[temp[i]].y)>d) break;
double d3=dist(temp[i],temp[j]);
if(d>d3&&node[temp[i]].id!=node[temp[j]].id)
d=d3;
}
}
return d;
}
int main()
{
int ncase,n;
scanf("%d",&ncase);
while(ncase--)
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%lf%lf",&node[i].x,&node[i].y);
node[i].id=1; ///1表示点位置
}
for(int i=n+1;i<=n*2;i++){
scanf("%lf%lf",&node[i].x,&node[i].y);
node[i].id=2; ///2表示人的位置
}
sort(node+1,node+1+2*n,cmpxy); ///排序,按x,y
printf("%.3f\n",solve(1,n*2));
}
return 0;
}