题目意思很简单,意思就是求一个图上最近点对。
具体思想就是二分法,这里就不做介绍,相信大家都会明白的,在这里我说明一下如何进行拼合。
具体证明一下为什么只需要检查6个点
首先,假设当前左侧和右侧的最小值为d,那么对于一个点,如果有个最小值小于d,那么一定存在于上d下d左d右d的一块区域内,又因为是从左到右,从上到下,所以左侧的那部分匹配的区域会重叠,也就是对于左侧的区域,完全没有必要去进行匹配。所以只需要对右侧d,上下d的区域进行匹配,而假设这个区域内的所以点的距离为d那么最多为6个,那么如果长度小于d那么根据抽屉原理可以知道最多为6个。
#include <iostream> #include <algorithm> #include <cstdio> #include <cmath> #define MaxN 100001 using namespace std; int N,t[MaxN],k; struct Posi{ double x,y; }point[MaxN]; bool compoint(Posi a,Posi b){ return a.x!=b.x?a.x<b.x:a.y<b.y; } bool comp(int a,int b){ return point[a].y<point[b].y; } inline double dist(int a,int b){ return sqrt((point[a].x-point[b].x)*(point[a].x-point[b].x)+(point[a].y-point[b].y)*(point[a].y-point[b].y)); } double solve(int l,int r){ if (l==r) return 1e30; if (l+1==r) return dist(l,r); int mid=(l+r)>>1; double ld=solve(l,mid); double rd=solve(mid+1,r); double d=min(ld,rd); k=0; for (int i=l;i<=r;i++) if (fabs(point[i].x-point[mid].x)<d) t[++k]=i; sort(t+1,t+k+1,comp); for (int i=1;i<k;i++) for (int j=i+1;j<=k && fabs(point[t[j]].y-point[t[i]].y)<d;j++){ double newd=dist(t[i],t[j]); if (newd<d) d=newd; } return d; } int main(){ while(cin>>N,N!=0){ for (int i=1;i<=N;i++) scanf("%lf%lf",&point[i].x,&point[i].y); sort(point+1,point+N+1,compoint); printf("%.2lf\n",solve(1,N)/2); } return 0; }