平面中最近的两点(分治法)

      设平面上的点按x排序好了,这样最多增加O(N*logN),这再整个算法来看并没有增加复杂度级别。
       排好序后,可以划一条垂线,把点集分成两半:PL和PR。于是最近点对或者在PL中,或者在PR中,或者PL,PR各有一点。
       把三种距离情况定义为dL, dR, dC.
 
        平面中最近的两点(分治法) - qhn999 - 码代码的猿猿     
       其中dL, dR可以递归求解,于是问题就变为计算dC。 根据上面红色字解释,由于我们希望得到O(N*logN)的解,因此必须能够仅仅多花O(N)的附加工作计算dC。
       另s=min(dL, dR). 通过观察能得出结论:如果dC<s,即dC对s有所改进,则只需计算dC。如果dC满足这样的条件,则决定dC的两点必然在分割线的s距离之内,称之为带(strip)
       否则不可能满足dC<s, 于是缩小了需要考虑的点的范围。      
         平面中最近的两点(分治法) - qhn999 - 码代码的猿猿
       如果是均匀分布的点集,则能证明出在该带中平均只有O(sqrt(N))个点,(注:书上这么写的,我也不会证,先记下这个理论吧)。因此,对这些点运用蛮力法可以在O(N)时间内完成。

#include <iostream>
#include <algorithm>
#include <cmath>
#include <iomanip>

#define MM 100020
using namespace std;

struct Note
{
    double x;
    double y;
}pt[MM];

int _sort1[MM];
int _sort2[MM];

double min(double& x,double& y)
{
    if(x-y>=1e-6)
       return y;
    else return x;
}

int cmp_x(const void *a,const void *b)
{
    if(((Note*)a)->x>((Note*)b)->x)  return 1;
    else return -1;
}

int cmp_y(const void *a,const void *b)
{
    if(((Note*)a)->y>((Note*)b)->y)  return 1;
    else return -1;
}
double distan(Note a,Note b)
{
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}

double neardis(int first,int ends)
{
    if(ends-first==1)  return distan(pt[first],pt[ends]);
    if(ends-first==2)  return min(min(distan(pt[first],pt[first+1]),distan(pt[first],pt[ends])),distan(pt[first+1],pt[ends]));
//2个点或3个点情况下返回
    int mid=(first+ends)/2;
    double dis1=neardis(first,mid);
    double dis2=neardis(mid+1,ends);
//划分问题
    double dota=min(dis1,dis2); 
    int _end1=0;
    int _end2=0;

    for(int i=mid;i>first&&distan(pt,pt[mid])<=dota;i--)
    {
        _sort1[_end1++]=i;
    }
    for(int i=mid+1;i<ends&&distan(pt,pt[mid])<=dota;i++)
    {
        _sort2[_end2++]=i;
    }
//统计在分界线两边的点的情况;
    double min_dis=dota;

    for(int i=0;i<_end1;i++)
    {
        for(int j=0;j<_end2;j++)
        {
            dota=distan(pt[_sort1],pt[_sort2[j]]);
            min_dis=min(min_dis,dota);
        }
    }
//计算在分界线两边的点的距离,与最小距离比较。
    return min_dis;
}

int main()
{
    int n;
    cin>>n;
    while(n)
    {
        for(int i=0;i<n;i++)
            cin>>pt.x>>pt.y;
        qsort(pt,n,sizeof(pt[0]),cmp_x);
        cout<<fixed<<setiosflags(ios::showpoint)<<setprecision(2)<<neardis(0,n-1)<<endl;
        cin>>n;
    }
    return 0;
}

原文地址:https://www.cnblogs.com/CKboss/p/3351142.html