问题描述
已知平面上分布着点集P
中的n
个点p1,p2,…pn,点i的坐标记为(xi,yi)
,1≤i≤n。两点之间的距离取其欧式距离。
问题:找出一对距离最近的点。
算法步骤
采用分治法。
记, dL:PL中的最近点对距离;dR:PR中的最近点对距离;dC:跨越分割线的最近点对距离
- 做分割线(垂线)将点集分为PL和PR两部分
- 递归地在PL中的找具有dL的点对
- 递归地在PR中的找具有dR的点对
- 在跨越分割线的点对中找具有dC的点对
- 返回min(dL,dR,dC)对应的点对。
主要思想:
在考虑跨越分割线时注意7
个点:
对坐标排序导致O(nlog2n)时间复杂度的改进:
算法实现
贴一份O(nlogn)的算法(实在不会写了QAQ):
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
int n;
struct node{
double x,y;
}p[200005],q[200005];
bool cmp(node a,node b){
return a.x<b.x;
}
double mergenode(int l,int r)
{
if(l==r)
return 100000000.0;
int mid=(l+r)>>1;
double ans=min(mergenode(l,mid),mergenode(mid+1,r)); //分治
int cnt=0;
for(int i=l;i<=r;++i)
if(fabs(p[i].x-p[mid].x)<ans)
q[++cnt]=p[i];
for(int i=1;i<cnt;++i) //暴力求解跨越分割线的点
for(int j=i+1;j<=cnt;++j)
ans=min(ans,sqrt((q[i].x-q[j].x)*(q[i].x-q[j].x)+(q[i].y-q[j].y)*(q[i].y-q[j].y)));
return ans;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;++i)
scanf("%lf%lf",&p[i].x,&p[i].y);
sort(p+1,p+n+1,cmp); //排序预处理
printf("%.4lf",mergenode(1,n));
return 0;
}