部分代码来源于kuangbin的几何模板
const double eps = 1e-8;
const double inf = 1e20;
const double pi = acos(-1.0);
const int maxp = 1010;
//`Compares a double to zero`
int sgn(double x){
if(fabs(x) < eps)return 0;
if(x < 0)return -1;
else return 1;
}
struct Point{
double x,y;
Point(){}
Point(double _x,double _y){
x = _x;
y = _y;
}
//叉积
double operator ^(Point b){
return x*b.y-y*b.x;
}
double cross(Point b,Point c){
return (b.x-x)*(c.y-y)-(b.y-y)*(c.x-x);
}
//点积
double operator *(Point b){
return x*b.x+y*b.y;
}
double dot(Point b,Point c){
return (b.x-x)*(c.x-x)+(b.y-y)*(c.y-y);
}
//两点间的距离
double distance(Point b){
return hypot(x-b.x,y-b.y);
}
//优先x然后y的坐标比较与排序
bool operator < (Point b)const{
return sgn(x-b.x)==0?sgn(y-b.y)<0:x<b.x;
}
//减
Point operator -(const Point &b)const{
return Point(x-b.x,y-b.y);
}
//判断相等
bool operator == (Point b)const{
return sgn(x-b.x)==0&&sgn(y-b.y)==0;
}
//加
Point operator + (const Point & b)const{
return Point(b.x+x,b.y+y);
}
//除double
Point operator /(const double &b)const {
return Point(x/b,y/b);
}
//乘double
Point operator *(const double &b)const {
return Point(x*b,y*b);
}
//向量逆时针旋转90度
Point rotleft(){
return Point(-y,x);
}
//向量顺时针旋转90度
Point rotright(){
return Point(y,-x);
}
//`绕着p点逆时针旋转angle`
Point rotate(Point p,double angle){
Point v = (*this) - p;
double c = cos(angle), s = sin(angle);
return Point(p.x + v.x*c - v.y*s,p.y + v.x*s + v.y*c);
}
//返回以当前点this为起点 this->b为方向 长度为r的点
Point mytrunc(Point b,double r){
double lens = distance(b);
Point unit = (b-(*this))/lens;
return Point (*this)+unit*r;
}
double linedis(Point b,Point c){
return fabs(cross(b,c))/b.distance(c);
}
};
struct Line{
Point s,e;
Line(){}
Line(Point _s,Point _e){
s = _s;
e = _e;
}
//直线和直线
//0重合
//1平行
//2相交
int linecorssline(Line v){
if(sgn((e-s)^(v.e-s))==0&&sgn((e-s)^(v.s-s))==0) return 0;
else if(sgn(((e-s)^(v.e-s))-((e-s)^(v.s-s)))==0) return 1;
return 2;
}
//求两直线的交点
Point crosspoint(Line v){
double a1 = (v.e-v.s)^(s-v.s);
double a2 = (v.e-v.s)^(e-v.s);
return Point((s.x*a2-e.x*a1)/(a2-a1),(s.y*a2-e.y*a1)/(a2-a1));
}
//线段之间的关系
//2 规范相交
//1 不规范相交(交于某一线段的端点)
//0 不相交
int segecross(Line v){
Point a=s,b=e,c=v.s,d=v.e;
int d1=sgn(a.cross(b,c));
int d2=sgn(a.cross(b,d));
int d3=sgn(c.cross(d,a));
int d4=sgn(c.cross(d,b));
if((d1^d2)==-2&&(d3^d4)==-2) return 2;
return(d1==0&&sgn(c.dot(a,b))<=0)||
(d2==0&&sgn(d.dot(a,b))<=0)||
(d3==0&&sgn(a.dot(c,d))<=0)||
(d4==0&&sgn(b.dot(c,d))<=0);
}
//点到线段的距离(最小距离)
double point_to_seg(Point a,Point b,Point c){
if(b==c) return a.distance(c);
if(sgn(b.dot(a,c))<0||sgn(c.dot(a,b))<0)
return min(a.distance(b),a.distance(c));
return a.linedis(b,c);
}
//线段到线段的最小距离
double seg_to_seg(Line v){
return min(min(point_to_seg(s,v.s,v.e),point_to_seg(e,v.s,v.e)),min(point_to_seg(v.s,s,e),point_to_seg(v.e,s,e)));
}
};
//////////////////圆
struct circle{
Point p;
double r;
circle (Point _p,double _r){
p = _p;
r = _r;
}
circle(Point a,Point b,Point c){
Line u = Line((a+b)/2,((a+b)/2)+((b-a).rotleft()));
Line v = Line((b+c)/2,((b+c)/2)+((c-b).rotleft()));
p = u.crosspoint(v);
r = p.distance(a);
}
//求两圆的公切线
//需要用到Point里面的mytrunc,distance
//测试 UVA10674
bool flag=false;//判断两圆是否进行过交换
Line ans[6];//所得的切线
int gettange(circle v){
Point a = p,Point b = v.p;double r1 = r,r2 = v.r;
int cnt=0;
if(a==b&&!sgn(r1-r2)) return -1;//重合 无数公切线
if(sgn(a.x-b.x)>0) swap(a,b),swap(r1,r2),flag=true;
double lens = a.distance(b),d = fabs(r1-r2);
if(sgn(lens-d)<0) return 0;//内含 无公切线
else if(sgn(lens-d)==0){//内切 一条公切线
if(sgn(r1-r2)>0) //注意判断半径
ans[1]=Line(a.mytrunc(b,r1),a.mytrunc(b,r1));
else ans[1]=Line(b.mytrunc(a,r2),b.mytrunc(a,r2));
return 1;
}
double ta,tb;//相离、外切、相交都有的两条切线
if(sgn(r1-r2)>0) ta=acos(d/lens),tb=pi-ta;
else tb=acos(d/lens),ta=pi-tb;
cnt++;ans[cnt].s=a.mytrunc(b.rotate(a,ta),r1),ans[cnt].e=b.mytrunc(a.rotate(b,-tb),r2);
cnt++;ans[cnt].s=a.mytrunc(b.rotate(a,-ta),r1),ans[cnt].e=b.mytrunc(a.rotate(b,tb),r2);
if(!sgn(lens-r1-r2)){//外切 多一条
cnt++;ans[cnt]=Line(a.mytrunc(b,r1),a.mytrunc(b,r1));
}else if(sgn(lens-r1-r2)>0){//相离 多两条
double l1=(lens/(r1+r2))*r1;
double l2=lens-l1;
ta=acos(r1/l1),tb=acos(r2/l2);
++cnt;ans[cnt].s=a.mytrunc(b.rotate(a,ta),r1),ans[cnt].e=b.mytrunc(a.rotate(b,tb),r2);
++cnt;ans[cnt].s=a.mytrunc(b.rotate(a,-ta),r1),ans[cnt].e=b.mytrunc(a.rotate(b,-tb),r2);
}
return cnt; //返回切线的个数
}
//最小圆覆盖 pt是点集 n是点数
circle(Point pt[],int n){
circle o(Point(0,0),0);
random_shuffle(pt+1,pt+1+n);
for(int i = 1; i <= n; i++){
if(sgn(o.r-o.p.distance(pt[i]))<0){
o=circle(pt[i],0);
for(int j = 1; j < i; j++){
if(sgn(o.r-o.p.distance(pt[j]))<0){
o.p=(pt[i]+pt[j])/2.0,o.r=o.p.distance(pt[i]);
for(int k = 1; k < j; k++){
if(sgn(o.r-o.p.distance(pt[k]))<0)
o=circle(pt[k],pt[i],pt[j]);
}
}
}
}
}
(*this)=o;
}
};
////////////////////////凸包
struct polygon{
int n;
Point p[maxp];
//极角排序的比较函数
struct cmp{
Point p;
cmp(const Point &p0){p = p0;}
bool operator()(const Point &aa,const Point &bb){
Point a = aa, b = bb;
int d = sgn((a-p)^(b-p));
if(d == 0){
return sgn(a.distance(p)-b.distance(p)) < 0;
}
return d > 0;
}
};
//`进行极角排序`
//`首先需要找到最左下角的点`
//`需要重载号好Point的 < 操作符(min函数要用) `
void norm(){
Point mi = p[0];
for(int i = 1;i < n;i++)mi = min(mi,p[i]);
sort(p,p+n,cmp(mi));
}
//凸包算法 返回凸包的点个数
//此算法得到的凸包顶点会按照逆时针排序
int Graham(Point q[]){
int top = -1;
sort(p,p+n);
q[++top]=p[0];q[++top]=p[1];
for(int i = 2; i < n; i++){
while(top>=1&&cross(q[top-1],q[top],p[i])<0) top--;//加上等于号得到纯净(不稳定凸包)
q[++top]=p[i];
}
int tp=top;
for(int i = n-2; i >= 0; i--){
while(top>=tp+1&&cross(q[top-1],q[top],p[i])<0) top--;
q[++top]=p[i];
}
return top;
}
////////////////////////////旋转卡壳
//凸包直径
double diameter(){
if(n==1) return 0;
int r = 1;
double ans = p[0].distance(p[r]);
for(int i = 0; i < n; i++){
Point p1=p[i],p2=p[(i+1)%n];
double s1=fabs((p[r]-p2)^(p1-p2)),s2=fabs((p[(r+1)%n]-p2)^(p1-p2));
while(sgn(s1-s2)<0){
r=(r+1)%n;
s1=fabs((p[r]-p2)^(p1-p2)),s2=fabs((p[(r+1)%n]-p2)^(p1-p2));
}
if(sgn(ans-p1.distance(p[r]))<0) ans=p1.distance(p[r]);
if(sgn(ans-p2.distance(p[r]))<0) ans=p2.distance(p[r]);
}
return ans;
}
//凸包宽度
double width(){
double ans = 1e9+100;
if(n<=2) return 0;
int r = 2;
for(int i = 0; i < n; i++){
Point p1=p[i],p2=p[(i+1)%n];
double s1=fabs((p[r]-p2)^(p1-p2)),s2=fabs((p[(r+1)%n]-p2)^(p1-p2));
while(sgn(s1-s2)<0){
r=(r+1)%n;
s1=fabs((p[r]-p2)^(p1-p2)),s2=fabs((p[(r+1)%n]-p2)^(p1-p2));
}
ans=min(ans,p[r].linedis(p1,p2));
}
return ans;
}
//两多边形之间的最近最远距离
//需要用到线段到线段最短距离 seg_to_seg(求最近的时候)
double getmindis(polygon b){
polygon a = (*this);
int i=0,j=0;
Point e=a.p[0],f=b.p[0];
for(int o = 1; o < a.n; o++)
if(a.p[o].y<e.y) e=a.p[o],i=o;
for(int o = 1; o < b.n; o++)
if(b.p[o].y>f.y) f=b.p[o],j=o;
a.p[a.n]=a.p[0],b.p[b.n]=b.p[0];
double ans = inf;
for(int o = 0; o < a.n; o++){
while(sgn(a.p[i+1].cross(b.p[j+1],a.p[i])-a.p[i+1].cross(b.p[j],a.p[i]))>0) j=(j+1)%b.n;
ans=min(ans,seg_to_seg(a.p[i],a.p[i+1],b.p[j],b.p[j+1]));
//最远距离就改成max
i=(i+1)%a.n;
}
return ans;
}
//`判断点和任意多边形的关系`(凹凸顺逆皆可)
//` 3 点上`
//` 2 边上`
//` 1 内部`
//` 0 外部`
int relationpoint(Point s){
int ans = 0;
for(int i = 0; i < n; i++){
if(s==p[i]) return 3;
int d = sgn(p[(i+1)%n].cross(s,p[i]));
if(d==0) {if(s.dot(p[i],p[(i+1)%n])<=0) return 2;}
else {
int u = sgn(p[i].y-s.y);
int v = sgn(p[(i+1)%n].y-s.y);
if(d > 0 && u < 0 && v >= 0)ans++;
if(d < 0 && v < 0 && u >= 0)ans--;
}
//printf("ans=%d\n",ans);
}
return ans!=0;
}
};
////////////////////平面最近点对
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int N = 1e5+100;
int n;
struct Point{
double x,y;
Point(){}
Point(double _x,double _y){
x = _x;
y = _y;
}
double dis(Point b){
return sqrt((x-b.x)*(x-b.x)+(y-b.y)*(y-b.y));
}
void input(){
scanf("%lf%lf",&x,&y);
}
}p[N],q[N];
bool cmp(Point a,Point b){
if(a.x==b.x) return a.y<b.y;
return a.x<b.x;
}
bool cmps(Point a,Point b){
return a.y<b.y;
}
double cdq(int l,int r){
if(l==r) return 2e9;
if(l+1==r) return p[l].dis(p[r]);
int mid = l+r>>1;
double d = min(cdq(l,mid),cdq(mid+1,r));
Point m = p[mid];
int tot = 0;
for(int i = l; i <= r; i++)
if(fabs(p[i].x-p[mid].x)<=d) q[++tot]=p[i];
sort(q+1,q+1+tot,cmps);
for(int i = 1; i <= tot; i++)
for(int j = i+1; j <= tot&& q[j].y-q[i].y<d; j++)
d=min(d,q[j].dis(q[i]));
return d;
}
int main(){
while(scanf("%d",&n)&&n){
for(int i = 1; i <= n; i++) p[i].input();
sort(p+1,p+1+n,cmp);
printf("%.2f\n",cdq(1,n));//输出最近距离
}
return 0;
}
//