#include <bits/stdc++.h>
#define endl '\n'
#define int long long
#define lint long long
#define pii pair<int, int>
#define FOR(i, a, b) for(int i = (a); i < (b); ++i)
#define FORR(i, a, b) for(int i = (a); i > (b); --i)
#define REP(i, n) FOR(i, 0, n)
#define SZ(v) ((int)v.size())
#define ZERO(a) memset(a, 0, sizeof(a))
#define MINUS(a) memset(a, 0xff, sizeof(a))
#define FILLINF(a) memset(a, 0x3f, sizeof(a))
#define POW(n) (1LL << (n))
#define POPCNT(n) (__builtin_popcount(n))
#define IN(i, a, b) ((a) <= (i) && (i) <= (b))
using namespace std;
template <typename T> inline bool CHMIN(T& a,T b) { if(a > b) { a = b; return 1; } return 0; }
template <typename T> inline bool CHMAX(T& a,T b) { if(a < b) { a = b; return 1; } return 0; }
template <typename T> inline void SORT(T& a) { sort(begin(a), end(a)); }
template <typename T> inline void REV(T& a) { reverse(begin(a), end(a)); }
template <typename T> inline void UNI(T& a) { sort(a.begin(), a.end()); a.erase(unique(a.begin(), a.end()), a.end()); }
template <typename S, typename T> inline T LB(S& v, T a) { return *lower_bound(begin(v), end(v), a); }
template <typename S, typename T> inline int LBP(S& v, T a) { return lower_bound(begin(v), end(v), a) - begin(v); }
template <typename S, typename T> inline T UB(S& v, T a) { return *upper_bound(begin(v), end(v), a); }
template <typename S, typename T> inline int UBP(S& v, T a) { return upper_bound(begin(v), end(v), a) - begin(v); }
template <typename S, typename T> ostream& operator << (ostream& os, const pair<S, T>& p) { os << p.first << " " << p.second; return os; }
template <typename S, typename T> istream& operator >> (istream& is, pair<S, T>& p) { is >> p.first >> p.second; return is; }
template <typename T> ostream& operator << (ostream& os, const vector<T>& v) { for (int i = 0; i < v.size(); ++i) { if (i) os << " "; os << v[i]; } return os; }
template <typename T> istream& operator >> (istream& is, vector<T>& v) { for(T& in : v) is >> in; return is; }
template <typename T = int> vector<T> make_v(size_t a) { return vector<T>(a); }
template <typename T, typename... Ts> auto make_v(size_t a, Ts... ts) { return vector<decltype(make_v<T>(ts...))>(a,make_v<T>(ts...)); }
template <typename T, typename V> typename enable_if<is_class<T>::value == 0>::type fill_v(T &t, const V &v) { t = v; }
template <typename T, typename V> typename enable_if<is_class<T>::value != 0>::type fill_v(T &t, const V &v) { for(auto &e : t) fill_v(e, v); }
// const double PI = 3.14159265358979323846;
// const double EPS = 1e-10;
// const lint INF = 0x3f3f3f3f3f3f3f3f;
const lint MOD = 1000000007;

using D = double;     // 座標値の型 doubleかlong double
using P = complex<D>; // Point
using L = pair<P, P>;  // Line
using VP = vector<P>;
const D EPS = 1e-10;   // 許容誤差
const D INF = 1e12;
const D PI = atan(1) * 4;
#define X real()
#define Y imag()
#define LT(n, m) ((n) + EPS < (m)) // n < m ?
#define LE(n, m) ((n) - EPS < (m)) // n <= m ?
#define GT(n, m) LT(m, n) // n > m ?
#define GE(n, m) LE(m, n) // n >= m ?
#define EQ(n, m) (abs((n) - (m)) < EPS)
#define NE(n, m) !EQ(n, m)

namespace std {
    istream& operator >> (istream& is, P& p) {
        D F, S;
        is >> F >> S;
        p = P(F, S);
        return is;
    }
    bool operator < (const P a, const P b) {
        return NE(a.X, b.X) ? LT(a.X, b.X) : LT(a.Y, b.Y);
    }
    bool operator > (const P a, const P b) {
        return NE(a.X, b.X) ? GT(a.X, b.X) : GT(a.Y, b.Y);
    }
    bool sort_y(const P a, const P b) {
        return LT(a.Y, b.Y);
    }
    void swap(P& a, P& b) {
        P c = a; a = b; b = c;
    }
}

// 内積
D dot(P a, P b) {
    return (conj(a) * b).X;
}

// 外積
D cross(P a, P b) {
    return (conj(a) * b).Y;
}

// 点aから見た、点bから点cへの方向
int ccw(P a, P b, P c) {
    b -= a; c -= a;
    if (GT(cross(b, c), 0)) return +1;      // counter clockwise
    if (LT(cross(b, c), 0)) return -1;      // clockwise
    if (LT(dot(b, c), 0)) return +2;        // c--a--b on line
    if (LT(norm(b), norm(c))) return -2;    // a--b--c on line or a==b
    return 0;                               // a--c--b on line or a==c or b==c
}

// ２直線の交点
P crosspointLL(P a1, P a2, P b1, P b2) {
    D d1 = cross(b2 - b1, b1 - a1);
    D d2 = cross(b2 - b1, a2 - a1);
    if (EQ(d1, 0) && EQ(d2, 0)) return a1;  // same line
    if (EQ(d2, 0)) throw "kouten ga nai";   // 交点がない
    return a1 + d1 / d2 * (a2 - a1);
}

// 三角形の外心．点a,b,cは同一線上にあってはならない
P circumcenter(P a, P b, P c) {
    if (ccw(a, b, c) == 2) return P((b.X + c.X) / 2, (b.Y + c.Y) / 2);
    if (ccw(a, b, c) == -2) return P((c.X + a.X) / 2, (c.Y + a.Y) / 2);
    if (ccw(a, b, c) == 0) return P((a.X + b.X) / 2, (a.Y + b.Y) / 2);
    a = (a - c) * 0.5;
    b = (b - c) * 0.5;
    return c + crosspointLL(a, a * P(1, 1), b, b * P(1, 1));
}

int N;

void _main() {
    cin >> N;
    VP ps(N);
    REP (i, N) cin >> ps[i];
    if (N == 2) {
        cout << abs(ps[0] - ps[1]) / 2 << endl;
        return;
    }
    D ans = INF;
    REP (i, N) FOR (j, i + 1, N) {
        P c((ps[i].X + ps[j].X) / 2, (ps[i].Y + ps[j].Y) / 2);
        D r = abs(c - ps[i]), tmp = 0;
        REP (l, N) {
            CHMAX(tmp, abs(ps[l] - c));
        }
        if (GT(tmp, r)) continue;
        CHMIN(ans, r);
    }
    REP (i, N) FOR (j, i + 1, N) FOR (k, j + 1, N) {
        P c = circumcenter(ps[i], ps[j], ps[k]);
        D r = abs(c - ps[i]), tmp = 0;
        REP (l, N) {
            CHMAX(tmp, abs(ps[l] - c));
        }
        if (GT(tmp, r)) continue;
        CHMIN(ans, r);
    }
    cout << ans << endl;
}

signed main(signed argc, char **argv) {
    if (argc > 1) {
        if (strchr(argv[1], 'i')) freopen("input.txt", "r", stdin);
        if (strchr(argv[1], 'o')) freopen("output.txt", "w", stdout);
    }
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout << fixed << setprecision(10);
    _main();
    return 0;
}

Measured memory_bytes: 256