一维
略。
二维
思想:
分治,排序
分治递归时,每次递归需要创造三个点集辅助比较,左右点集以及两者之间形成点对的点的点集
将n个点以横纵坐标为关键字进行排序,选取中间一点为分界点,将n个点分为两个点集;此时递归下去求出两点集各自的最近点对距离h1和h2;此时根据递归已求出h1和h2,选取其中最小的值作为h值,因为除了两点集内部的最小点集求出以外,还有两点集之间的点对距离未作比较;此时选取横坐标与参照点横坐标距离小于h的分别来自于左点集和右点集的点作为可能构成答案的点,将这些点单独放入一个点集;将得到的点集按照点的纵坐标进行排序并依次遍历该点集,对于每个点遍历纵坐标小于它但距离不超过h的点求出点对距离并更新答案,最终答案要么是h要么是更新后的答案。
时间复杂度:分治需要进行log2(n)次,每次分治通过巧妙借助归并排序已知可达到O(n)的复杂度,总复杂度为O(nlogn)
代码实现:
#include<bits/stdc++.h>
#include<algorithm>
#define ll long long
#define maxn 20000
#define INF 0x3f3f3f3f
using namespace std;
int n;
struct Point{
double x;
double y;
}pt[maxn],tmpt[maxn];
int cmp(Point a,Point b){
return (a.x<b.x||(a.x==b.x&&a.y<b.y));
}
int cmpy(Point a,Point b)
{
return (a.y<b.y);
}
double dist(Point a,Point b){
return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
double closest_pair(int l,int r)
{
if(l==r)
return INF;
if(l+1==r)
return dist(pt[l],pt[r]);
int mid=(r+l)/2;
double d1 = closest_pair(l, mid);
double d2 = closest_pair(mid + 1, r);
double d = min(d1, d2);
int cnt=0;
for(int i=l;i<=r;i++)
if(fabs(pt[i].x-pt[mid].x)<d)
tmpt[cnt++]=pt[i];
sort(tmpt,tmpt+cnt,cmpy);//创建临时数组
for(int i=0;i<cnt;i++)
for(int j=i-1;j>=0&&(tmpt[i].y-tmpt[j].y)<d;j--)
d=min(d,dist(tmpt[i],tmpt[j]));
return d;
}
int main()
{
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%lf%lf",&pt[i].x,&pt[i].y);
sort(pt,pt+n,cmp);
double ans=closest_pair(0,n-1);
ans*=ans;
printf("%.0f",ans);
system("pause");
}