Problem:
Score : 600 points

Problem Statement

Given are N points (x_i, y_i) in a two-dimensional plane.

Find the minimum radius of a circle such that all the points are inside or on it.

Constraints

2 \leq N \leq 50

0 \leq x_i \leq 1000

0 \leq y_i \leq 1000

The given N points are all different.

The values in input are all integers.

Input

Input is given from Standard Input in the following format:

N
x_1 y_1
:
x_N y_N

Output

Print the minimum radius of a circle such that all the N points are inside or on it.

Your output will be considered correct if the absolute or relative error from our answer is at most 10^{-6}.

Sample Input 1

2
0 0
1 0

Sample Output 1

0.500000000000000000

Both points are contained in the circle centered at (0.5,0) with a radius of 0.5.

Sample Input 2

3
0 0
0 1
1 0

Sample Output 2

0.707106781186497524

Sample Input 3

10
10 9
5 9
2 0
0 0
2 7
3 3
2 5
10 0
3 7
1 9

Sample Output 3

6.726812023536805158

If the absolute or relative error from our answer is at most 10^{-6}, the output will be considered correct.

Solution in C++14 (GCC 5.4.1) (judge verdict: Accepted)

#include <bits/stdc++.h>
using namespace std;
using lint = long long int;
using pint = pair<int, int>;
using plint = pair<lint, lint>;
struct fast_ios { fast_ios(){ cin.tie(0); ios::sync_with_stdio(false); cout << fixed << setprecision(20); }; } fast_ios_;
#define ALL(x) (x).begin(), (x).end()
#define SZ(x) ((lint)(x).size())
#define POW2(n) (1LL << (n))
#define FOR(i, begin, end) for(int i=(begin),i##_end_=(end);i<i##_end_;i++)
#define IFOR(i, begin, end) for(int i=(end)-1,i##_begin_=(begin);i>=i##_begin_;i--)
#define REP(i, n) FOR(i,0,n)
#define IREP(i, n) IFOR(i,0,n)
template<typename T> void ndarray(vector<T> &vec, int len) { vec.resize(len); }
template<typename T, typename... Args> void ndarray(vector<T> &vec, int len, Args... args) { vec.resize(len); for (auto &v : vec) ndarray(v, args...); }
template<typename T> bool mmax(T &m, const T q) { if (m < q) {m = q; return true;} else return false; }
template<typename T> bool mmin(T &m, const T q) { if (m > q) {m = q; return true;} else return false; }
template<typename T1, typename T2> pair<T1, T2> operator+(const pair<T1, T2> &l, const pair<T1, T2> &r) { return make_pair(l.first + r.first, l.second + r.second); }
template<typename T1, typename T2> pair<T1, T2> operator-(const pair<T1, T2> &l, const pair<T1, T2> &r) { return make_pair(l.first - r.first, l.second - r.second); }
template<typename T> istream &operator>>(istream &is, vector<T> &vec){ for (auto &v : vec) is >> v; return is; }
///// This part below is only for debug, not used /////
template<typename T> ostream &operator<<(ostream &os, const vector<T> &vec){ os << "["; for (auto v : vec) os << v << ","; os << "]"; return os; }
template<typename T> ostream &operator<<(ostream &os, const deque<T> &vec){ os << "deq["; for (auto v : vec) os << v << ","; os << "]"; return os; }
template<typename T> ostream &operator<<(ostream &os, const set<T> &vec){ os << "{"; for (auto v : vec) os << v << ","; os << "}"; return os; }
template<typename T> ostream &operator<<(ostream &os, const unordered_set<T> &vec){ os << "{"; for (auto v : vec) os << v << ","; os << "}"; return os; }
template<typename T> ostream &operator<<(ostream &os, const multiset<T> &vec){ os << "{"; for (auto v : vec) os << v << ","; os << "}"; return os; }
template<typename T> ostream &operator<<(ostream &os, const unordered_multiset<T> &vec){ os << "{"; for (auto v : vec) os << v << ","; os << "}"; return os; }
template<typename T1, typename T2> ostream &operator<<(ostream &os, const pair<T1, T2> &pa){ os << "(" << pa.first << "," << pa.second << ")"; return os; }
template<typename TK, typename TV> ostream &operator<<(ostream &os, const map<TK, TV> &mp){ os << "{"; for (auto v : mp) os << v.first << "=>" << v.second << ","; os << "}"; return os; }
template<typename TK, typename TV> ostream &operator<<(ostream &os, const unordered_map<TK, TV> &mp){ os << "{"; for (auto v : mp) os << v.first << "=>" << v.second << ","; os << "}"; return os; }
#define dbg(x) cerr << #x << " = " << (x) << " (L" << __LINE__ << ") " << __FILE__ << endl;
///// END /////

using T_P = double;
constexpr T_P EPS = 1E-12;

struct P
{
    T_P x, y;
    P() : x(0), y(0) {}
    P(T_P x, T_P y) : x(x), y(y) {}
    P(pair<T_P, T_P> p) : x(p.first), y(p.second) {}
    static T_P add_w_error(T_P a, T_P b) { return (abs(a + b) < EPS * (abs(a) + abs(b))) ? 0 : a + b; }
    P operator+(const P &p) const { return P(add_w_error(x, p.x), add_w_error(y, p.y)); }
    P &operator+=(const P &p) { return *this = *this + p; }
    P operator-(const P &p) const { return P(add_w_error(x, -p.x), add_w_error(y, -p.y)); }
    P &operator-=(const P &p) { return *this = *this - p; }
    P operator*(const P &p) const { return P(add_w_error(x * p.x, -y * p.y), add_w_error(x * p.y, y * p.x)); }
    P operator*(T_P d) const { return P(x * d, y * d); }
    P operator/(T_P d) const { return P(x / d, y / d); }
    P inv() const { return conj() / norm2(); }
    P operator/(const P &p) const { return (*this) * p.inv(); }
    bool operator<(const P &r) const{ return x != r.x ? x < r.x : y < r.y; }
    bool operator==(const P &r) const{ return add_w_error(x, -r.x) == 0 and add_w_error(y, -r.y) == 0; }
    T_P dot(P p) const { return add_w_error(x * p.x, y * p.y); }
    T_P det(P p) const { return add_w_error(x * p.y, -y * p.x); }
    T_P norm() const { return sqrt(x * x + y * y); }
    T_P norm2() const { return x * x + y * y; }
    // rotate point/vector by rad
    P rotate(T_P rad) { return P(add_w_error(x * cos(rad), -y * sin(rad)), add_w_error(x * sin(rad), y * cos(rad))); }
    P normalize() const { return (*this) / norm(); }
    P conj() const { return P(x, -y); }
    friend istream &operator>>(istream &is, P &p) { T_P x, y; is >> x >> y; p = P(x, y); return is; }
    friend ostream &operator<<(ostream &os, const P &p) { os << '(' << p.x << ',' << p.y << ')'; return os; }
};

int ccw(P a, P b, P c) // a->b->cの曲がり方
{
    P v1 = b - a;
    P v2 = c - a;
    if (v1.det(v2) > EPS) return 1; // 左折
    if (v1.det(v2) < -EPS) return -1; // 右折
    if (v1.dot(v2) < -EPS) return 2; // c-a-b
    if (v1.norm() < v2.norm()) return -2; // a-b-c
    return 0; // a-c-b
}


// Convex hull （凸包）
// return: IDs of vertices used for convex hull, counterclockwise
// include_boundary: If true, interior angle pi is allowed
vector<int> convex_hull(const vector<P> &ps, bool include_boundary=false)
{
    int n = ps.size();
    if (n <= 1) return vector<int>(n, 0);
    vector<pair<P, int>> points(n);
    for (size_t i = 0; i < ps.size(); i++) points[i] = make_pair(ps[i], i);
    sort(points.begin(), points.end());
    int k = 0;
    vector<pair<P, int> > qs(2 * n);
    auto ccw_check = [&](int c) {
        if (include_boundary) return c == -1;
        else return c <= 0;
    };
    for (int i = 0; i < n; i++)
    {
        while (k > 1 and ccw_check(ccw(qs[k - 2].first, qs[k - 1].first, points[i].first))) k--;
        qs[k++] = points[i]; 
    }
    for (int i = n - 2, t = k; i >= 0; i--) {
        while (k > t and ccw_check(ccw(qs[k - 2].first, qs[k - 1].first, points[i].first))) k--;
        qs[k++] = points[i];
    }
    vector<int> ret(k - 1);
    for (int i = 0; i < k - 1; i++) ret[i] = qs[i].second;
    return ret;
}

// Circumcenter （三角形の外心）
// - raise exception for collinear points
P circumcenter(P z1, P z2, P z3) {
    assert(abs(ccw(z1, z2, z3)) % 2 == 1);
    P a = z2 - z1, b = z3 - z1;
    return z1 + a * b * (a - b).conj() / (b * a.conj() - a * b.conj());
}


int main()
{
    int N;
    cin >> N;
    vector<P> X(N);
    cin >> X;
    P p;
    double dx = 500, r = 0;
    while (dx > 1e-9) {
        P maxi;
        r = 0;
        for (auto x : X) {
            if (mmax(r, (x - p).norm())) maxi = x;
        }
        p += (maxi - p).normalize() * dx;
        dx *= 0.999;
    }
    cout << r << endl;
}