【算法·分治】平面最近点对

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Ronaldo7_ZYB/article/details/88817700

问题

给定平面上n个点,找出其中的一对点的距离,使得在这n个点的所有点对中,该距离为所有点对中最小的

做法

将每一个点按照横坐标排序,然后分治区间 [ 1 , n ] [1,n] .

再内一个递归函数内:

  • 和归并排序的思想类似,可以递归左区间 [ l , m i d ] [l,mid] 找到左边的平面最近点对,距离是 d 1 d1 ,同理,可以递归找到右区间 [ r , m i d ] [r,mid] 的平面最近点对,距离是 d 2 d2 。那么当前最优解 d = m i n ( d 1 , d 2 ) . d=min(d1,d2). 这分别是两边的平面最近点对。
  • 我们还需要找到横跨在中间mid中的最近点对,那么和中间点距离大于d的一定不是最优解,对于每一个保存的点则有 X [ i ] X [ m i d ] d X[i]-X[mid] \leq d 。然后为了方便比较,我们对这一些点按照纵坐标排序;然后双重循环暴力枚举,只要总坐标距离大于d就退出(因为根据排序,以后的答案只会越来越不优),否则统计答案即可。

代码如下:

#include <bits/stdc++.h>
using namespace std;
struct node {
    double x,y;
}a[300000];
int temp[300000];
inline bool cmp(node p1,node p2)
{
    return p1.x<p2.x;
}
inline bool Cmp(int p1,int p2)
{
    return a[p1].y<a[p2].y;
}
inline double dis(int p1,int p2)
{
    double x=a[p1].x-a[p2].x;
    double y=a[p1].y-a[p2].y;
    return sqrt(x*x+y*y);
}
inline double min(int a,int b)
{
    if (a>b) return b;
    else return a;
}
double dfs(int l,int r)
{
    double Min=1e10;
    if (l>=r) return Min;
    if (l+1==r) return dis(l,r);
    int mid=l+r>>1,cnt=0;
    Min=min(dfs(l,mid),dfs(mid+1,r));
    for (int i=l;i<=r;++i)
         if (fabs(a[i].x-a[mid].x)<=Min) 
             temp[++cnt]=i;
    sort(temp+1,temp+cnt+1,Cmp);
    for (int i=1;i<cnt;++i)
        for (int j=i+1;j<=cnt;++j)
        {
            if (fabs(a[temp[i]].y-a[temp[j]].y)>=Min) break;
            Min=min(Min,dis(temp[i],temp[j]));
        }
    return Min; 
}
int main(void)
{
    int n;
    scanf("%d",&n);
    for (int i=1;i<=n;++i)
        scanf("%lf %lf",&a[i].x,&a[i].y);
    sort(a+1,a+n+1,cmp);	
    printf("%.4lf\n",dfs(1,n));
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Ronaldo7_ZYB/article/details/88817700
今日推荐