分治
关键在于,最后合并的时候,取x = ps[mid].x,往左右划x - mindis,x + mindis的线,最近对还可能出现在这个带状区域中
虽然可以对x左边的点在右边的区域找,但是十分不好找到他对应的点,还不如全部放在一起,按y排序,从下向上找更好。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <vector>
using namespace std;
const int maxn =1e5 + 5;
struct point{
double x,y;
bool operator < (constpoint &a) const{
return x < a.x || (x == a.x &&y < a.y);
}
}ps[maxn],tmp[maxn];
int n;
double mindis;
bool cmp(constpoint &a,constpoint &b){
return a.y < b.y;
}
double getdis(point &p1,point &p2)
{
return (p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y);
}
void merge(int l,int mid,int r)//如果从左边对右边求的话,不好找,还是把区间的全部放在一起按y排序,从下往上数6个更好
{
double x = ps[mid].x;
vector<point> v;
for (int i = l; i <= r; i ++) {
if(x - mindis <=ps[i].x && ps[i].x <= x + mindis) v.push_back(ps[i]);
}
sort(v.begin(),v.end(),cmp);
for (int i =0 ; i < v.size(); i ++) {
for (int j =1; j <= 6 && i + j < v.size(); j ++) {
mindis = min(mindis,getdis(v[i], v[i +j]));
}
}
}
void closet_point_pair(int l,int r)
{
if(r - l == 1){// 2 points
mindis = min(mindis,getdis(ps[l],ps[l + 1]));
}
else if(r - l ==2){// 3 points
mindis = min(mindis,getdis(ps[l],ps[l + 1]));
mindis = min(mindis,getdis(ps[l],ps[r]));
mindis = min(mindis,getdis(ps[r -1], ps[r]));
}
else{
int mid = (l + r) / 2;
closet_point_pair(l, mid);
closet_point_pair(mid + 1, r);
merge(l,mid,r);
}
}
int main()
{
while (scanf("%d",&n) !=EOF) {
if(n ==0) break;
for (int i =0; i < n; i ++) {
scanf("%lf%lf",&ps[i].x,&ps[i].y);
}
sort(ps,ps +n);
mindis = getdis(ps[0],ps[1]);
closet_point_pair(0,n -1);
printf("%.2lf\n",sqrt(mindis) /2);
}
return 0;
}