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# (Mono 4.6.2.0) (judge verdict: Accepted)

using System;
using System.Linq;
using System.Collections.Generic;

namespace Contest
{
    partial class Program
    {
        static void Main(string[] args)
        {
            ABC151F();
        }

        static void ABC151A()
        {
            var s = ReadStr();
            Console.WriteLine((char)(s[0] + 1));
        }
        static void ABC151B()
        {
            var nkm = ReadIntN();
            var A = ReadIntN();
            var N = nkm[0];
            var K = nkm[1];
            var M = nkm[2];
            var goal = N * M - A.Sum();
            Console.WriteLine(goal > K ? -1 : (goal < 0 ? 0 : goal));
        }
        static void ABC151C()
        {
            var nm = ReadIntN();
            var PS = ReadTupleStr(nm[1]);
            var N = nm[0];
            int[] ac = new int[N + 1];
            int[] wa = new int[N + 1];
            foreach(var ps in PS)
            {
                var n = Convert.ToInt32(ps.Item1);
                if (ps.Item2 == "AC")
                {
                    ac[n] = 1;
                }
                else
                {
                    if (ac[n] == 0) { wa[n]++; }
                }
            }
            long countAC = ac.Sum();
            long countWA = Enumerable.Range(0, ac.Length).Select(i => ac[i] > 0 ? wa[i] : 0).Sum();
            Console.WriteLine("{0} {1}", countAC, countWA);
        }
        static void ABC151D()
        {
            var hw = ReadIntN();
            var H = hw[0];
            var W = hw[1];
            bool[,] road = new bool[H + 2, W + 2];
            for (int h = 0; h < H; ++h)
            {
                var str = ReadStr();
                for (int w = 0; w < W; ++w)
                {
                    road[h + 1, w + 1] = str[w] == '.';
                }
            }
            Tuple<int, int>[] moves = new Tuple<int, int>[] { new Tuple<int, int>(-1, 0), new Tuple<int, int>(1, 0), new Tuple<int, int>(0, -1), new Tuple<int, int>(0, 1) };
            int max = 0;
            for(int startH = 1; startH <= H; ++startH)
            {
                for(int startW = 1; startW <= W; ++startW)
                {
                    if (!road[startH, startW]) { continue; }
                    bool[,] done = new bool[H + 2, W + 2];
                    List<Tuple<int,int>> list = new List<Tuple<int, int>>();
                    done[startH, startW] = true;
                    list.Add(new Tuple<int, int>(startH, startW));
                    int counter = -1;
                    while (list.Count > 0)
                    {
                        List<Tuple<int, int>> next = new List<Tuple<int, int>>();
                        foreach (var t in list)
                        {
                            foreach(var move in moves)
                            {
                                var h = t.Item1 + move.Item1;
                                var w = t.Item2 + move.Item2;
                                if(!done[h,w] && road[h, w])
                                {
                                    done[h, w] = true;
                                    next.Add(new Tuple<int, int>(h, w));
                                }
                            }
                        }
                        list = next;
                        counter++;
                    }
                    max = Math.Max(max, counter);
                }
            }
            Console.WriteLine(max);
        }
        static void ABC151E()
        {
            var nk = ReadIntN();
            var A = ReadLongN();
            var N = nk[0];
            var K = nk[1];
            A = A.OrderBy(x => x).ToArray();
            var combFunc = Util.Combin(N, Util.P);
            long sumMax = 0;
            long sumMin = 0;
            for(int i = 0; i < N; ++i)
            {
                sumMax = (sumMax + combFunc(i, K - 1) * A[i]) % Util.P;
                sumMin = (sumMin + combFunc(N - i - 1, K - 1) * A[i]) % Util.P;
            }
            Console.WriteLine((sumMax - sumMin + Util.P * 10) % Util.P);
        }
        static void ABC151F()
        {
            var N = ReadInt();
            var XY = ReadTupleDouble(N);
            double eps = 1e-8;

            double min = Double.MaxValue;

            /// 最小の半径を与える円は以下のいずれか
            /// (1) ある2点を直径とする
            /// (2) ある3点を通る

            for (int i = 0; i < N; ++i)
            {
                var I = XY[i];
                for (int j = i + 1; j < N; ++j)
                {
                    var J = XY[j];

                    /// ある2点を直径とする
                    {
                        ///中心o 半径r
                        var o = Geometric.Center(I, J);
                        var r = Geometric.Distance(o, I);

                        /// 全点がoからr以内にあればOK
                        if (!Enumerable.Range(0, N).Any(l => Geometric.Distance(XY[l], o) > r + eps))
                        {
                            min = Math.Min(min, r);
                        }
                    }

                    /// ある3点を通る
                    /// 線分(I,J)の垂直二等分線 a1 x + b1 y + c1 =0
                    var bs1 = Geometric.Bisector(I, J);
                    for (int k = j + 1; k < N; ++k)
                    {
                        var K = XY[k];
                        /// 線分(I,K)の垂直二等分線 a2 x + b2 y + c2 =0
                        var bs2 = Geometric.Bisector(I, K);

                        /// 垂直二等分線が平行＝3点が同一直線上にあるので円は存在しない
                        if (Geometric.IsParallel(bs1, bs2, eps))
                        {
                            continue;
                        }

                        /// 垂直二等分線の交点が円の中心
                        var o = Geometric.Intersection(bs1, bs2);
                        var r = Geometric.Distance(o, I);

                        /// 全点がoからr以内にあればOK
                        if (!Enumerable.Range(0, N).Any(l => Geometric.Distance(XY[l], o) > r + eps))
                        {
                            min = Math.Min(min, r);
                        }
                    }
                }
            }
            Console.WriteLine(min);
        }


        class Util
        {
            public static readonly long P = 1000000007;

            public static Dictionary<long,int> Factorize(long x)
            {
                var dict = new Dictionary<long, int>();
                long minp = 2;
                while (x > 1)
                {
                    bool ok = false;
                    for(long p = minp; p * p <= x; ++p)
                    {
                        if (x % p == 0)
                        {
                            if (!dict.ContainsKey(p))
                            {
                                dict.Add(p, 0);
                            }
                            dict[p]++;
                            minp = p;
                            x /= p;
                            ok = true;
                            break;
                        }
                    }
                    if (!ok)
                    {
                        if (!dict.ContainsKey(x)) { dict.Add(x, 0); }
                        dict[x]++;
                        break;
                    }
                }
                return dict;
            }
            public static long Inverse(long a, long p)
            {
                long b = p, c = 1, d = 0, e = 0, f = 0;
                while (b != 0)
                {
                    e = a / b;
                    f = b; b = a - e * b; a = f;
                    f = d; d = c - e * d; c = f;
                }
                c %= p;
                return c + (c < 0 ? p : 0);
            }
            public static long[] Facts(int n, long p)
            {
                var facts = new long[n + 1];
                facts[0] = 1;
                for (int i = 1; i <= n; ++i)
                {
                    facts[i] = (i * facts[i - 1]) % p;
                }
                return facts;
            }
            public static Func<int,int,long> Combin(int n, long P)
            {
                var fact = Facts(n, P);
                var inv = fact.Select(x => Inverse(x, P)).ToArray();
                return (N, M) =>
                {
                    if (N < 0 || N < M || M < 0) { return 0; }
                    return (((fact[N] * inv[M]) % P) * inv[N - M]) % P;
                };
            }
        }
        class Geometric
        {
            /// <summary>
            /// 2点間の距離
            /// </summary>
            public static double Distance(Tuple<double, double> s, Tuple<double, double> t)
            {
                var diff1 = s.Item1 - t.Item1;
                var diff2 = s.Item2 - t.Item2;
                return Math.Sqrt(diff1 * diff1 + diff2 * diff2);
            }
            /// <summary>
            /// 2点の中点
            /// </summary>
            public static Tuple<double,double> Center(Tuple<double, double> s, Tuple<double, double> t)
            {
                return new Tuple<double, double>((s.Item1 + t.Item1) / 2, (s.Item2 + t.Item2) / 2);
            }

            /// <summary>
            /// 垂直二等分線 ax+by+c=0の係数(a,b,c)を出力
            /// </summary>
            public static Tuple<double,double,double> Bisector(Tuple<double, double> s, Tuple<double, double> t)
            {
                var a = t.Item1 - s.Item1;
                var b = t.Item2 - s.Item2;
                var c = -a * (s.Item1 + t.Item1) / 2 - b * (s.Item2 + t.Item2) / 2;
                return new Tuple<double, double, double>(a, b, c);
            }

            /// <summary>
            /// 2本の直線が平行か(絶対誤差Epsilon)
            /// </summary>
            public static bool IsParallel(Tuple<double, double, double> line1, Tuple<double, double, double> line2, double epsilon)
            {
                return Math.Abs(line1.Item1 * line2.Item2 - line1.Item2 * line2.Item1) < epsilon;
            }

            /// <summary>
            /// 2本の直線の交点(平行でないことを仮定)
            /// </summary>
            public static Tuple<double,double> Intersection(Tuple<double, double, double> line1, Tuple<double, double, double> line2)
            {
                var div = line1.Item1 * line2.Item2 - line1.Item2 * line2.Item1;
                var x = (line1.Item2 * line2.Item3 - line1.Item3 * line2.Item2) / div;
                var y = (line1.Item3 * line2.Item1 - line1.Item1 * line2.Item3) / div;
                return new Tuple<double, double>(x, y);
            }
        }

        static string ReadStr()
        {
            return Console.ReadLine();
        }
        static string[] ReadStrN()
        {
            return Console.ReadLine().Split(' ');
        }
        static int ReadInt()
        {
            return Convert.ToInt32(Console.ReadLine());
        }
        static int[] ReadIntN()
        {
            return Console.ReadLine().Split(' ').Select(s => Convert.ToInt32(s)).ToArray();
        }
        static long ReadLong()
        {
            return Convert.ToInt64(Console.ReadLine());
        }
        static long[] ReadLongN()
        {
            return Console.ReadLine().Split(' ').Select(s => Convert.ToInt64(s)).ToArray();
        }
        static Tuple<string, string>[] ReadTupleStr(int n)
        {
            List<Tuple<string, string>> list = new List<Tuple<string, string>>();
            for (int i = 0; i < n; ++i)
            {
                var ab = ReadStrN();
                list.Add(new Tuple<string, string>(ab[0], ab[1]));
            }
            return list.ToArray();
        }
        static Tuple<long, long>[] ReadTupleLong(int n)
        {
            List<Tuple<long, long>> list = new List<Tuple<long, long>>();
            for (int i = 0; i < n; ++i)
            {
                var ab = ReadLongN();
                list.Add(new Tuple<long, long>(ab[0], ab[1]));
            }
            return list.ToArray();
        }
        static Tuple<double, double>[] ReadTupleDouble(int n)
        {
            List<Tuple<double, double>> list = new List<Tuple<double, double>>();
            for (int i = 0; i < n; ++i)
            {
                var ab = ReadLongN();
                list.Add(new Tuple<double, double>(ab[0], ab[1]));
            }
            return list.ToArray();
        }
    }
}