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;
}
posted @ 2021-06-23 10:39  acmloser  阅读(69)  评论(0编辑  收藏  举报