#include <iostream>
#include<stdio.h>
#include<cmath>
#define N 100
using namespace std;
struct Dian
{
int x;
int y;
};
chushihua(int x[],int n)
{
for(int i=0;i<n;i++)
{
x[i]=i;
}
return 0;
}
input(struct Dian d[],int n)
{
for(int i=0;i<n;i++)
{
cin>>d[i].x>>d[i].y;
}
return 0;
}
output(struct Dian d[],int n)
{
for(int i=0;i<n;i++)
{
cout<<'('<<d[i].x<<','<<d[i].y<<')'<<' ';
if(i%5==4)
{
cout<<endl;
}
}
return 0;
}
output_(int X[],int n)
{
for(int i=0;i<n;i++)
{
cout<<X[i]<<' ';
if(i%5==4)
{
cout<<endl;
}
}
return 0;
}
swap(int *p1,int *p2)
{
int a=*p1;
*p1=*p2;
*p2=a;
return 0;
}
swap(struct Dian *p1,struct Dian *p2)
{
int a=p1->x,b=p1->y;
p1->x=p2->x;p1->y=p2->y;
p2->x=a;p2->y=b;
return 0;
}
hebing(struct Dian d[],int m,int n,int z,int X[])//二分归并排序用合并函数
{
int c[n-m+1];
struct Dian b[n-m+1];
int j=(m+n)/2+1,k=0,i=m;
if(z==1)
{
while(i<=(n+m)/2||j<=n)
{
while((d[i].x>d[j].x||i>(m+n)/2)&&j<=n)
{
b[k].x=d[j].x;
b[k].y=d[j].y;
k++;
j++;
}
while((d[i].x<=d[j].x||j>n)&&i<=(m+n)/2)
{
b[k].x=d[i].x;
b[k].y=d[i].y;
k++;
i++;
}
}
for(int i=m,k=0;i<=n;i++,k++)
{
d[i].x=b[k].x;
d[i].y=b[k].y;
}
}
else if(z==2)
{
while(i<=(n+m)/2||j<=n)
{
while((d[X[i]].y>d[X[j]].y||i>(m+n)/2)&&j<=n)
{
c[k]=X[j];
k++;
j++;
}
while((d[X[i]].y<=d[X[j]].y||j>n)&&i<=(m+n)/2)
{
c[k]=X[i];
k++;
i++;
}
}
for(int i=m,k=0;i<=n;i++,k++)
{
X[i]=c[k];
}
}
return 0;
}
paixu(struct Dian d[],int m,int n,int z,int X[])//二分归并排序
{
if(z==1)
{
if(n-m>=2)
{
paixu(d,m,(m+n)/2,z,X);
paixu(d,(m+n)/2+1,n,z,X);
hebing(d,m,n,z,X);
}
else if(n-m==1)
{
if(d[m].x>d[n].x)
{
swap(d+m,d+n);
}
return 0;
}
else if(n==m)
{
return 0;
}
}
if(z==2)
{
if(n-m>=2)
{
paixu(d,m,(m+n)/2,z,X);
paixu(d,(m+n)/2+1,n,z,X);
hebing(d,m,n,z,X);
}
else if(n-m==1)
{
if(d[X[m]].y>d[X[n]].y)
{
swap(X+m,X+n);
}
return 0;
}
else if(n==m)
{
return 0;
}
}
return 0;
}
double min_mid(int m,int n,int X[],int YL[],int YR[],struct Dian d[],double dis)
//求点集最小距离时处理分界线两边dis窄缝间的最小距离
{
int yL[(n+m)/2+1],yR[(n+m)/2+1];
int lx=0,rx=0,ly=0,ry=0;//lx为左边窄缝第一个点序号,rx为右边最后一点序号
for(int i=m;i<=n;i++)//把中间窄缝的点按x坐标分别放入两个数组
{
if(d[i].x>=d[(m+n)/2].x-dis&&d[i].x<=d[(m+n)/2].x)
{
lx=i;
i=(m+n)/2+1;
}
if(d[i].x<=d[(m+n)/2].x+dis&&d[i].x>=d[(m+n)/2].x)
{
rx=i;
}
}
if(rx==0)
{
return(dis);
}
for(int i=0;i<=(n-m)/2;i++)//把窄缝的点按y坐标顺序放入两个数组
{
if(YL[i]>=lx)
{
yL[ly]=YL[i];
ly++;
}
}
for(int i=0;i<=(n-m)/2-1;i++)//把窄缝的点按y坐标顺序放入两个数组
{
if(YR[i]<=rx)
{
yR[ry]=YR[i];
ry++;
}
}
int ry1=0,ry11[ry]={0};
//ry1是用来标记右边是否有点在正负dis之间,ry11[ry]用来存放第一个在范围内的点的序号
//因为是按y坐标来计算最小距离,左边下面的点在右边能找到的第一个在dis范围内的点才是他上面那个点需要开始考虑的起止点
//这样可以防止每次检索右侧点从第0个开始
for(int i=0;i<ly;i++)//比较窄缝左右两边点的距离
{
for(int j=ry11[0];j<ry;j++)
{
if(d[yR[j]].y<d[yL[i]].y+dis)
{
ry11[0]=ry;//初始化下一个点的比较的右侧起始位置,防止右边y值最大的点也不在范围内
if(d[yR[j]].y>d[yL[i]].y-dis)
{
dis=min(sqrt(pow(d[yL[i]].x-d[yR[j]].x,2)+pow(d[yL[i]].y-d[yR[j]].y,2)),dis);
ry11[ry1]=j;ry1++;
//只有ry1=0时是记录第一个在范围内的点,后续记录信息无用,只是让程序不要覆盖第一个点的信息。
}
}
}
ry1=0;
}
return(dis);
}
double mindistance(int m,int n,int X[],int Y[],struct Dian d[])
{
if(n-m==1)
{
return(sqrt(pow(d[n].x-d[m].x,2)+pow(d[n].y-d[m].y,2)));
}
else if(n-m==2)
{
return(min(sqrt(pow(d[n].x-d[m].x,2)+pow(d[n].y-d[m].y,2)),min(sqrt(pow(d[n].x-d[m+1].x,2)+pow(d[n].y-d[m+1].y,2)),sqrt(pow(d[n-1].x-d[m].x,2)+pow(d[n-1].y-d[m].y,2)))));
}
else
{
int YL[(n-m+1)/2],YR[(n-m+1)/2];
int yl=0,yr=0;
double dis=0;
for(int i=m;i<=n;i++)
{
if(Y[i]<=(n+m)/2)
{
YL[yl]=Y[i];
yl++;
}
else
{
YR[yr]=Y[i];
yr++;
}
}
double a=mindistance(m,(m+n)/2,X,YL,d);
double b=mindistance((m+n)/2+1,n,X,YR,d);
dis=min(a,b);
dis=min_mid(m,n,X,YL,YR,d,dis);
return(dis);
}
}
int main()
{
freopen("input.txt","r",stdin);
struct Dian Dianji[N];
int X[N]={0},Y[N]={0};
int n;
cin>>n;
input(Dianji,n);
chushihua(X,n);
chushihua(Y,n);
output(Dianji,n);
paixu(Dianji,0,n-1,1,X);//按x坐标排序结果
output(Dianji,n);//按x坐标排序结果
output_(X,n);//按x坐标排序结果
paixu(Dianji,0,n-1,2,Y);//按Y坐标排序结果
output_(Y,n);//按Y坐标排序结果
cout<<mindistance(0,n-1,X,Y,Dianji)<<endl;
return 0;
}