P1429 平面最近点对(加强版)
原题链接
考察:分治
经典题了,问题是这种分治本蒟蒻真的想不到()
思路:
思路以及证明看这位大佬的博客,没有比他写的更好的. GO
但是这位大佬的图感觉有点问题,后面枚举y坐标时,日字应该是横着才对.
时间复杂度\(O(nlog_2n)\)
Code
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
const int N = 200010;
const double eps = 1e-5;
struct Node{
double x,y;
}node[N];
int n;
struct cmp1{
bool operator()(Node a,Node b){//x为第一关键字
if(fabs(a.x-b.x)<=eps) return a.y<b.y;
return a.x<b.x;
}
};
struct cmp2{
bool operator()(Node a,Node b){
if(fabs(a.y-b.y)<=eps) return a.x<b.x;
return a.y<b.y;
}
};
double Dist(Node a,Node b)
{
double d1 = a.x-b.x;
double d2 = a.y-b.y;
return sqrt(d1*d1+d2*d2);
}
double solve(int l,int r)
{
sort(node+l,node+r+1,cmp1());//x坐标排序
double ans = 2e9;
if(r-l<=3)
{
for(int i=l;i<=r;i++)
for(int j=i+1;j<=r;j++)
ans = min(Dist(node[i],node[j]),ans);
}else{
int mid = l+r>>1;
ans = min(solve(l,mid),ans);
ans = min(solve(mid+1,r),ans);
vector<Node> v;//存储竖条的点
for(int i=l;i<=r;i++)
if(fabs(node[i].x-node[mid].x)<=ans)
v.push_back(node[i]);
sort(v.begin(),v.end(),cmp2());//纵坐标排序
for(int i=0;i<v.size();i++)
for(int j=i+1;j<v.size();j++)
{
Node a = v[i],b = v[j];
double d = Dist(a,b);
if(d>ans) break;
ans = min(d,ans);
}
}
return ans;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%lf%lf",&node[i].x,&node[i].y);
printf("%.4lf\n",solve(1,n));
return 0;
}