dp-最小点对问题

dp-最小点对问题

//最小点对问题
//采用分治思想,先分成两个子集分别求出最短距离d
//再对两个子集进行合并,在一个dx2d的矩形中,最多可能有6个点距离小于d
//按y排序,当x增长时求出这6个点的最小距离d2
//ans=min(d,d2),O(nlogn)

#include<stdio.h>
#include<time.h>
#include<math.h>
#include<algorithm>


#define LENGTH 100001
#define INF 1e20

struct point
{
    double x;
    double y;
}p[LENGTH],tmp[LENGTH];

double dist(point a,point b) { return sqrt(pow(a.x-b.x,2)+pow(a.y-b.y,2)); }
double min(double a,double b) { return a<b?a:b; }
bool cpx(point a,point b) { return a.x<b.x; }
bool cpy(point a,point b) { return a.y<b.y; }

double mindist(int l,int r)
{
    double d=INF;
    if(r==l)
        return d;
    if(r-l==1)
        return dist(p[l],p[r]);
    if(r-l==2)
        return min(dist(p[l],p[l+1]),min(dist(p[l],p[r]),dist(p[l+1],p[r])));

    int mid=(r+l)>>1;
    d=min(mindist(l,mid),mindist(mid+1,r));

    int k=0;
    for(int i=l;i<=r;i++)
        if(fabs(p[i].x-p[mid].x)<=d)
        {
            tmp[k++]=p[i];
            if(k>5) break;//最多只有6个点
        }
    std::sort(tmp,tmp+k,cpy);
    for(int i=0;i<k;i++)
        for(int j=i+1;j<k&&tmp[j].y-tmp[i].y<d;j++)
        {
            double t=dist(tmp[i],tmp[j]);
            if(t<d) d=t;
        }

    return d;
}

int main()
{
    while(1)
    {
        int n;
        scanf("%d",&n);
        if(n==0) break;

        for(int i=0;i<n;i++)
            scanf("%lf%lf",&p[i].x,&p[i].y);
        std::sort(p,p+n,cpx);
        printf("%.2f
",mindist(0,n-1)/2);
    }
}
  • 测试用例

输入样例:

    2

    0 0

    1 1

    2

    1 1

    1 1

    3

    -1.5 0

    0 0

    0 1.5

    0

  输出样例:

    0.71

    0.00

    0.75

原文地址:https://www.cnblogs.com/yueshangzuo/p/7834047.html