题目的意思是求输出平面最近点对距离的一半。
分治法找平面最近点对的过程
1 把整个点集按x排序
2 根据x坐标,将点集A分成左右两边点集R和点集L,根据迭代分别求R中和L中的最近点对,得到min_dist
3 如果点集A中还存在更小的点对,则肯定是一个点在R中另外一个点在L中的情况。并且候选点离R和L的分割线的距离都小于min_dist
4 将候选点按y坐标排序。根据画图可知,如果R中的点a和L中的点b有可能构成最小点对,则a和b在按y排序后的数组中最多相差7个位置。说简单点,就是在 2min_dist*min_dist的范围内,最多存在8个候选点(中间有两对点重合)。
5 按4的思路,限定范围后枚举候选点,查找是否有距离小于min_dist的点对。
按照算法导论上的介绍,整个算法的时间复杂度有T(n)=T(n/2)+O(n),T(n)=O(n*lgn)。
但第四步y排序那个部分我不知道该怎么实现O(n),我是用的常规排序,效率是O(n*lgn)。于是有T(n)=T(n/2)+O(n*lgn),T(n)=O(n*lgn*lgn)。
枚举那部分我用了两种方法,提交后一种跑了2.1s,另一种跑了1.6s。
#include "math.h" #include <iostream> using namespace std; struct Node { double x,y; }pt[100005]; int Y_sort[100005]; double MinN(double a,double b) { if(a<b) return a; else return b; } inline double Distance(Node &a,Node &b) { return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)); } int CMP_X(const void *a,const void *b) { if(((Node*)a)->x<((Node*)b)->x) return -1; else return 1; } int CMP_Y(const void *a,const void *b) { if(pt[(*(int*)a)].y<pt[(*(int*)b)].y) return -1; else return 1; } double Nearest_Point_Distance(int first,int end)//first end 指点在pt数组中的下标,并假设pt已经按x排序 { if(end-first==1) return Distance(pt[first],pt[first+1]); else if(end-first==2) return MinN(MinN(Distance(pt[first],pt[first+1]),Distance(pt[first+1],pt[first+2])),Distance(pt[first],pt[first+2])); int mid=(first+end)/2; double min_dist=MinN(Nearest_Point_Distance(first,mid),Nearest_Point_Distance(mid+1,end)); int Y_end=0; for(int i=mid;i>=first&&(pt[mid].x-pt[i].x)<min_dist;i--) { Y_sort[Y_end++]=i; } for(int i=mid+1;i<=end&&(pt[i].x-pt[mid+1].x)<min_dist;i++) { Y_sort[Y_end++]=i; } qsort(Y_sort,Y_end,sizeof(Y_sort[0]),CMP_Y); /*for(int i=0;i<Y_end;i++) { for(int j=1;j<8&&i+j<Y_end;j++) { min_dist=MinN(min_dist,Distance(pt[Y_sort[i]],pt[Y_sort[i+j]])); } }*/ for(int i=0;i<Y_end;i++)//上面那种也可以,但貌似速度慢点 { for(int j=i+1;j<Y_end&&pt[Y_sort[j]].y-pt[Y_sort[i]].y<min_dist;j++) { min_dist=MinN(min_dist,Distance(pt[Y_sort[i]],pt[Y_sort[j]])); } } return min_dist; } int main() { int n; while (scanf("%d",&n)&&n) { for (int i=0;i<n;i++) scanf("%lf%lf", &pt[i].x, &pt[i].y); qsort(pt,n,sizeof(pt[0]),CMP_X); printf("%.2f/n", Nearest_Point_Distance(0,n-1)/2); } return 0; }