最近点的距离

215 阅读1分钟

题目:最近点的距离

网址 http://10.129.27.27/contest/17/problem/1001

image.png

image.png

思路

  • 采用分治的思想。主要是两部分的合并,可取以x=mid的中垂线左右距离为d的所有点。可把数据简化为常数级。然后对每个点检查y方向距离为d的点来求出最小的距离,可以证明在另一半区间点数最多6个。 注意
  • 不一定要找到完美的解法,能够减小计算量也非常不错。!!
  • 不要把判断语句放到for里面循环for(int i=low;i<=mid&&abs(points[mid].x-points[i].x)<=d;i++)会提前退出,应该用if判断,如下
	for(int i=low;i<=mid;i++){
		if(abs(points[mid].x-points[i].x)<=d)p[index++]=points[i];		
	}

代码

#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn=1000001;
const double INF=0x3f3f3f3f;
int n;
struct Point{
	double x,y;
};
Point points[maxn];

bool cmpX(Point a,Point b){
	if(a.x!=b.x) return a.x<b.x;
	else return a.y<b.y;
}
bool cmpY(Point a,Point b){
	return a.y<b.y;
}
double Distance(Point a,Point b){
	return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
int countx=0;
Point p[maxn];
double closest(int low,int high){
	if(high==low) return INF;  //一个输入INF 
	else if(high-low==1) return Distance(points[low],points[high]); //两个直接输出距离 
	int mid=(low+high)/2;
	double d1,d2,d3,d;
	d1=closest(low,mid);  //分治两个区间 
	d2=closest(mid+1,high);
	d=min(d1,d2);
	int index=0;
	for(int i=low;i<=mid;i++){  //找中垂线两端距离d的点 
		if(abs(points[mid].x-points[i].x)<=d) p[index++]=points[i];		
	}
	sort(p,p+index,cmpY);
	for(int i=0;i<index;i++){  // 找一点上下距离为d的点 
		for(int j=i+1;j<index&&p[j].y-p[i].y<=d;j++){
			d3=Distance(p[i],p[j]);
			if(d3<d) {
				d=d3;
				countx++;
			}
		}
	}
	return d;
}
int main(){
	int n;cin >> n;
	for(int i=1;i<=n;i++)scanf("%lf%lf",&points[i].x,&points[i].y);
	sort(points+1,points+1+n,cmpX);
	double d=closest(1,n);
	if(d<10000) printf("%.4lf\n",closest(1,n));
	else printf("INFINITY");
	return 0;
}