分治算法应用-最近点对的最小距离-hdu 1007 Quoit Design

 

采用分治的思想,把n个点按照x坐标进行排序,以坐标mid为界限分成左右两个部分,对左右两个部分分别求最近点对的距离,然后进行合并。对于两个部分求得的最近距离d,合并过程中应当检查宽为2d的带状区间是否有两个点分属于两个集合而且距离小于d,最多可能有n个点,合并时间最坏情况下是O(n^2).但是,左边和右边中的点具有以下稀疏的性质,对于左边中的任意一点,右边的点必定落在一个d*2d的矩形中,且最多只需检查6个点(鸽巢原理),这样,先将带状区间的点按照y坐标进行排序,然后线性扫描,这样合并的时间复杂度为O(nlogn)。

#include <bits/stdc++.h>

using namespace std;
const int inf=0x3f3f3f3f;
const int N=1e5+10;
int n;
struct Point
{
    double x,y;
} a[N],b[N];

bool cmpx(const Point a,const Point b)
{
    return a.x<b.x;
}

bool cmpy(const Point a,const Point b)
{
    return a.y<b.y;
}

double dis(Point a,Point b)
{
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}


double solve(int l,int r)
{
    if (l==r)
    {
        return inf;
    }
    int mid=(l+r)>>1,tail=0;
    double d=min(solve(l,mid),solve(mid+1,r));
    for (int i=mid; i>=l&&a[mid].x-a[i].x<d; i--)
    {
        b[tail++]=a[i];
    }
    for (int i=mid+1; i<=r&&a[i].x-a[mid].x<d; i++)
    {
        b[tail++]=a[i];
    }
    sort(b,b+tail,cmpy);
    for (int i=0; i<tail; i++)
    {
        for (int j=i+1; j<tail&&b[j].y-b[i].y<d; j++)
        {
            d=min(d,dis(b[i],b[j]));
        }
    }
    return d;
}



int main()
{
    while (scanf("%d",&n))
    {
        if (!n)
        {
            break;
        }
        for (int i=1; i<=n; i++)
        {
            scanf("%lf%lf",&a[i].x,&a[i].y);
        }
        sort(a+1,a+n+1,cmpx);
        double ans=solve(1,n)/2;
        printf("%.2lf
",ans);
    }
}

  

原文地址:https://www.cnblogs.com/Accpted/p/11262728.html