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

给定平面上的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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值