这题主要就是几何问题中的分治
将集合划分为S1和S2,根据平衡子问题原则,每个子集中大约有N/2个点,设集合S的最近点对为P1和P2;
1.最近点对在集合S1中;
2.最近点对在集合S2中;
3.最近点对在集合S1和S2中;
对于情况1和2比较简单直接递归求解;但第三种情况稍微麻烦一些,在1,2的基础上求中间两边的点距离在1和2中的dmini值内可能存在的情况点,在那这些点进行计算和之进行比较,从而求得结果;
#include <stdio.h>
#include <math.h>
#include <algorithm>
using namespace std;
struct point
{
double x,y;
};
point s[100005];
bool cmpx(point a,point b) //排序
{
if (a.x == b.x)
return a.y < b.y;
else
return a.x < b.x;
}
bool cmpy(point a,point b) //排序
{
if (a.y == b.y)
return a.x < b.x;
else
return a.y < b.y;
}
double ddistance(point a,point b) //计算两点之间的距离
{
return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
double closest(int low,int high)
{
double d1,d2,d3,d;
int mid,index;
point p[100005]; //存放点集合
if(high-low==1) //只有两个点直接返回距离
{
return ddistance(s[low],s[high]);
}
if(high-low==2) //只有三个点,直接求
{
d1=ddistance(s[low],s[low+1]);
d2=ddistance(s[low+1],s[high]);
d3=ddistance(s[low],s[high]);
if(d1<d2&&d1<d3) return d1;
else if(d2<d3) return d2;
else return d3;
}
mid=(low+high)/2; // 计算中间点
d1=closest(low,mid); //递归求解子问题 1
d2=closest(mid+1,high); //递归求解子问题 2
if(d1<d2) d=d1; //求解子问题 3
else d=d2;
index=0;
for(int i=mid;(i>=low)&&(s[mid].x-s[i].x<d);i--) //建立集合点P1
{
p[index++]=s[i];
}
for(int i=mid+1;(i<=high)&&(s[i].x-s[mid].x<d);i++) //建立集合点P2
{
p[index++]=s[i];
}
sort(p,p+index,cmpy); //对集合点P1和P2按y坐标升序排序
for(int i=0;i<index;i++) //一次处理集合中的点
{
for(int j=1+i;j<=7&&j<=index;j++)
{
if(p[i].y-p[j].y>=d)
{
break;
}
else{
d3=ddistance(p[i],p[j]);
if(d3<d) d=d3;
}
}
}
return d;
}
int main()
{
int n;
double dd;
while(scanf("%d",&n),n)
{
for(int i=0;i<n;i++)
{
scanf("%lf%lf",&s[i].x,&s[i].y);
}
sort(s,s+n,cmpx);
dd=closest(0,n-1)/2;
printf("%.2lf\n",dd);
}
return 0;
}