题目地址:点击打开链接
一道典型的分治法求最小点对的问题,很难搞懂,请参考大神的博客:点击打开链接
以下是代码实现,耗时889ms,已经相当快了,注意如果用cin输入的话会超时。
/*分治法求最小点对*/
#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<iomanip>
using namespace std;
struct point {
double x,y;
}p[100005],*px[100005],*py[100005];
double cmpx(point *a,point *b)
{
if(a->x==b->x)
return a->y<b->y;
return a->x<b->x;
}
double cmpy(point *a,point *b)
{
return a->y<b->y;
}
double dis(point *a,point *b)
{
return sqrt((a->x-b->x)*(a->x-b->x)+(a->y-b->y)*(a->y-b->y));
}
double min(double a,double b)
{
return a<b?a:b;
}
double find(int s,int e)
{
if(s+1==e)
return dis(px[s],px[e]);
if(s+2==e)
return min(dis(px[s],px[s+1]),min(dis(px[s+1],px[e]),dis(px[s],px[e])));
int mid=(s+e)>>1;
double ans=min(find(s,mid),find(mid+1,e));
int i,j,cnt=0;
for(i=s;i<=e;i++)
{
if(px[i]->x>=px[mid]->x-ans&&px[i]->x<=px[mid]->x+ans)
py[cnt++]=px[i];
}
sort(py,py+cnt,cmpy);//按y坐标排序
for(i=0;i<cnt;i++)
{
for(j=i+1;j<cnt;j++)
{
if(py[j]->y-py[i]->y>=ans)
break;
ans=min(ans,dis(py[i],py[j]));
}
}
return ans;
}
int main()
{
long long n,i;
while(scanf("%d",&n)!=EOF&&n)
{
for(i=0;i<n;i++)
{
scanf("%lf%lf",&p[i].x,&p[i].y);
px[i]=&p[i];
}
sort(px,px+n,cmpx);
double dis=find(0,n-1)/2;
cout<<fixed<<setprecision(2)<<dis<<endl;
}
return 0;
}