<pre class="cpp" name="code"><strong><span style="font-size:18px;">这题直接暴力会tle,正确解法是分治:先按x坐标排序分左右两个区间,求出这两个区间内的最小距离,然后处理两个点在中线左右两边的情况,这时候只考虑分布在中线两侧距离在d之内的点,同时这些点的y方向距离也应在d之内,这样总的复杂度就能够控制在O(nlogn),具体在区间内的点的个数上限好像是7,不过推导过程比较麻烦没太看懂,总之在处理中间得点时需要处理的数量是O(n)的</span></strong>
#include<iostream>
#include<string>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<cmath>
#define REP(n) for(int R=0;R<(n);R++)
typedef long long i64;
#define MX 100005
using namespace std;
typedef pair<double,double> P;////(x,y)
P A[MX];
int N;
bool cmp_y(P a,P b){
return a.second<b.second;///按照y排序的比较函数
}
double closest_pair(P *a,int sz){///进入函数时是按照x排序的
if(sz<=1)
return 1e100;
int m=sz/2;
double midx=a[m].first;///中间值
double d=min(closest_pair(a,m),closest_pair(a+m,sz-m));///递归处理左右区间的最小d
inplace_merge(a,a+m,a+sz,cmp_y);///此时(递归处理后)左右两区间已经按y排好序了,
///使用stl的归并排序,复杂度O(n)
vector<P> B;
for(int i=0;i<sz;i++){
if(abs(a[i].first-midx)<d){///x方向距离限制
for(int j=B.size()-1;j>=0;j--){
double dx=B[j].first-a[i].first,dy=B[j].second-a[i].second;
if(abs(dy)>=d)///从后往前检查y方向距离是否小于d
break;
d=min(d,sqrt(dx*dx+dy*dy));
}
B.push_back(a[i]);
}
}
return d;
}
int main(){
while(cin>>N,N){
REP(N)scanf("%lf%lf",&A[R].first,&A[R].second);
sort(A,A+N);
printf("%.2lf\n",closest_pair(A,N)/2);
}
return 0;
}