版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Ronaldo7_ZYB/article/details/88817700
问题
给定平面上n个点,找出其中的一对点的距离,使得在这n个点的所有点对中,该距离为所有点对中最小的
做法
将每一个点按照横坐标排序,然后分治区间 .
再内一个递归函数内:
- 和归并排序的思想类似,可以递归左区间 找到左边的平面最近点对,距离是 ,同理,可以递归找到右区间 的平面最近点对,距离是 。那么当前最优解 这分别是两边的平面最近点对。
- 我们还需要找到横跨在中间mid中的最近点对,那么和中间点距离大于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;
}