#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include <string.h>

#define INF 9999999
#define BASE 2

int N;

typedef struct {//頂点情報格納用
    double x, y;
    int v;//頂点番号を持っておくと、Divide and Conquerで散り散りになっても値を追える
} Vertex;

Vertex V_INF = {INF, INF, INF};

typedef struct {//最近点対（距離と頂点番号）格納用
    int i, j;
    double length;
} Result;


void init(Vertex *);
Result n2_search(Vertex *, int);//力任せな解法
double Get_Distance(Vertex, Vertex);//距離を求める（力任せ用）
Result DC(Vertex *, int, int);//分割統治法による解法
void mergesort(Vertex *, Vertex *);


int main() {
    scanf("%d", &N);

    Vertex *V;
    Result res;

    V = (Vertex *) malloc(sizeof(Vertex) * N);

    int i;
    for (i = 0 ;i < N; ++i) {
      scanf("%lf%lf", &V[i].x, &V[i].y);
    }

    // x座標でソート
    mergesort(V, V + N);

    res = DC(V, 0, N);//Divide and Conquer
    if (res.j < res.i) {
        int tmp = res.i;
        res.i = res.j;
        res.j = tmp;
    }
    printf("%.7f\n", res.length);

    free(V);

    return 0;
}


void init(Vertex *V) {//乱数でデータ生成
    int i;

    srand(time(NULL));
    for (i = 0; i < N; i++) {
        V[i].x = 100 * (double) rand() / RAND_MAX;
        V[i].y = 100 * (double) rand() / RAND_MAX;
        V[i].v = i;
        printf("%d) %f, %f \n", V[i].v, V[i].x, V[i].y);
    }

    printf("****************************************\n");
}


Result n2_search(Vertex *V, int n) {//力任せ
    int i, j;
    double min_dist = INF, dist;
    Result res;

    for (i = 0; i < n - 1; i++) {
        for (j = i + 1; j < n; j++) {
            if (i == j)continue;
            dist = Get_Distance(V[i], V[j]);
            if (dist < min_dist) {
                min_dist = dist;
                res.i = V[i].v;
                res.j = V[j].v;
            }
        }
    }

    res.length = min_dist;
    return res;
}


double Get_Distance(Vertex V1, Vertex V2) {
    double dist;

    dist = sqrt((V2.x - V1.x) * (V2.x - V1.x) + (V2.y - V1.y) * (V2.y - V1.y));

    return dist;
}

void merge(Vertex *first, Vertex *mid, Vertex *last) {
    const int N1 = (int) (mid - first);
    const int N2 = (int) (last - mid);
    Vertex *left = malloc(sizeof(Vertex) * (N1 + 1));
    Vertex *right = malloc(sizeof(Vertex) * (N2 + 1));
    memcpy(left, first, sizeof(Vertex) * (N1 + 1));
    memcpy(right, mid, sizeof(Vertex) * (N2 + 1));
    left[N1] = right[N2] = V_INF;
    Vertex *it;
    int i, j;
    for (it = first, i = 0, j = 0; it != last; ++it) {
        *it = left[i].x <= right[j].x ? left[i++] : right[j++];
    }
    free(left);
    free(right);
}

void mergesort(Vertex *first, Vertex *last) {
    const int n = (int) (last - first);
    if (n < 2) return;
    Vertex *mid = first + n / 2;
    mergesort(first, mid);
    mergesort(mid, last);
    merge(first, mid, last);
}

void merge_y(Vertex *first, Vertex *mid, Vertex *last) {
    const int N1 = (int) (mid - first);
    const int N2 = (int) (last - mid);
    Vertex *left = malloc(sizeof(Vertex) * (N1 + 1));
    Vertex *right = malloc(sizeof(Vertex) * (N2 + 1));
    memcpy(left, first, sizeof(Vertex) * (N1 + 1));
    memcpy(right, mid, sizeof(Vertex) * (N2 + 1));
    left[N1] = right[N2] = V_INF;
    Vertex *it;
    int i, j;
    for (it = first, i = 0, j = 0; it != last; ++it) {
        *it = left[i].y <= right[j].y ? left[i++] : right[j++];
    }
    free(left);
    free(right);
}

Result DC(Vertex *v, int first, int last) {
    const int n = last - first;
    int mid = first + n / 2;
    double x = v[mid].x;

    // BASE以下のサイズで全探索
    if (n <= BASE) {
        Result res = n2_search(v + first, n);
        // y座標でソート
        merge_y(v + first, v + mid, v + last);
        return res;
    }

    Result d1 = DC(v, first, mid);
    Result d2 = DC(v, mid, last);
    Result d = d1.length <= d2.length ? d1 : d2;

    // y座標でソート
    merge_y(v + first, v + mid, v + last);

    // 左右にまたがる頂点対を探索
    Vertex *over = malloc(n * sizeof(Vertex));
    int t = 0;
    int i, j;
    for (i = first; i < last; ++i) {
        if (fabs(v[i].x - x) >= d.length) continue;

        for (j = t - 1; j >= 0; --j) {
            double dy = v[i].y - over[j].y;
            if (dy >= d.length) break;

            Result d3 = {v[i].v, over[j].v, Get_Distance(v[i], over[j])};
            d = d3.length <= d.length ? d3 : d;
        }
        over[t++] = v[i];
    }

    free(over);

    return d;
}

