最近点对问题(UVa 10245)(分治)

来源:互联网 发布:iphone清楚应用数据 编辑:程序博客网 时间:2024/05/21 21:02

给定平面上的n个点,求距离最近的两个点的距离。

限制条件:

1<=n<=10000


思路:假设我们把所有点按x坐标分成了左右两半,那么最近点对的距离就是下面二者的最小值:

(1)2点p和q同属于左半边或右半边时点对(p,q)的距离;

(2)2点p和q属于不同区域时点对(p,q)的距离;

首先,对于(1)可以通过递归计算;对于(2),我们可以利用(1)部分的最小值,不妨记为d,再考虑下面的(2‘):

(2‘)2点p和q属于不同区域时,距离小于d的点对(p,q)的距离;

接下来,我们考虑x坐标:假设将点划分为左右两半的直线为l,其x坐标为x0,那么根据(2‘),到直线l的距离大于等于d的点就没有必要考虑了,我们只需要考虑x坐标满足x0-d<x<x0+d的点即可;考虑y坐标:对于每个点,都只需要考虑与那些y坐标不比自己大的点组成的点对(或比自己大的)(单方向考虑,避免重复计算点对),也就是说,对于y坐标为yp的点,我们只需要考虑y坐标满足yp-d<y<=yp的点即可;

综上所述,我们要检查的点都在x0-d<x<x0+d且yp-d<y<=yp的矩形区域内。

时间复杂度:递归的深度为O(logn),而每一层有O(n)个操作,所以总的复杂度是O(nlogn);


代码:

typedef pair<double,double> P;//first保存x坐标,second保存y坐标//输入int N;P A[MAX_N];//用于按y坐标归并的比较函数bool compare_y(P a,P b){     return a.second<b.second;}//传入的a已经按x坐标排好序了double closest_pair(P *a,int n){     if(n<=1) return INF;     int m=n/2;     double x=a[m].first;     double d=min(closest_pair(a,m),closest_pair(a+m,n-m));//(1)     inplace_merge(a,a+m,a+n,compare_y);//归并两个排好序的数列,STL中inplace_merge函数点击打开链接     //此时,a已经按y坐标排好序了     //(2‘)    vector<P> b;//将到直线的距离小于d的顶点加入    for(int i=0;i<n;i++){         if(fabs(a[i].first-x)>=b)   continue;         //从后往前检查(因为y坐标递增,故倒着检查)b中y坐标相差小于d的点         for(int j=0;j<b.size();j++){             double dx=a[i].first-b[b.size()-j-1].first;             double dy=a[i].second-b[b.size()-j-1].second;             if(dy>=d)  break;             d=min(d,sqrt(dx*dx+dy*dy));          }         b.push_back(a[i]);     }     retuen d;}void solve(){     sort(A,A+N);//按x坐标排序     printf("%f\n",closest_pair(A,N)0;}


原创粉丝点击