题目:最近点的距离
网址 http://10.129.27.27/contest/17/problem/1001
思路
- 采用分治的思想。主要是两部分的合并,可取以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;
}