Language: C++

#pragma GCC optimize("Ofast")
#define _USE_MATH_DEFINES
#include "bits/stdc++.h"

using namespace std;

using u8 = uint8_t;
using u16 = uint16_t;
using u32 = uint32_t;
using u64 = uint64_t;
using i8 = int8_t;
using i32 = int32_t;
using i64 = int64_t;

constexpr char newl = '\n';
constexpr double eps = 1e-10;

#define FOR(i,a,b) for (int i = (a); i < (b); i++)
#define F0R(i,b) FOR(i,0,b)
#define RFO(i,a,b) for (int i = ((b)-1); i >=(a); i--)
#define RF0(i,b) RFO(i,0,b)
//#define fi first
//#define se second
#define debug(x) cout << #x << ": " << x << '\n';
#define rng(a) a.begin(),a.end()
#define rrng(a) a.rbegin(),a.rend()

template<typename T1, typename T2> inline void chmin(T1& a, T2 b) { if (a > b) a = b; }
template<typename T1, typename T2> inline void chmax(T1& a, T2 b) { if (a < b) a = b; }
template<class T> void Print(vector<T> v) {
  F0R(i, v.size()) {
    cout << v[i] << ' ';
  }
  cout << newl;
}

#if 1

template<typename T>
constexpr T Abs(T a) {
  return a > 0 ? a : -a;
}
template<class T>
struct Vector2D {
  T X, Y;

  Vector2D(T x = 0, T y = 0) :X(x), Y(y) {}

  constexpr T MagnitudeSqr() const {
    return X * X + Y * Y;
  }

  constexpr T DistanceSqr(const Vector2D<T>& r) const {
    double a = r.X - X, b = r.Y - Y;
    return a * a + b * b;
  }

  constexpr double Distance(const Vector2D<T>& r) const {
    return sqrt(DistanceSqr(r));
  }

  Vector2D<T>& operator+=(const Vector2D<T>& r) {

    X += r.X;
    Y += r.Y;

    return *this;
  }

  friend Vector2D<T> operator+(Vector2D<T> l, const Vector2D<T>& r) {
    l += r;
    return l;
  }

  Vector2D<T>& operator-=(const Vector2D<T>& r) {

    X -= r.X;
    Y -= r.Y;

    return *this;
  }

  friend Vector2D<T> operator-(Vector2D<T> l, const Vector2D<T>& r) {
    l -= r;
    return l;
  }

  template<class N>
  Vector2D<T>& operator*=(const N& r) {

    X *= r;
    Y *= r;

    return *this;
  }

  template<class N>
  friend Vector2D<T> operator*(Vector2D<T> l, const N& r) {
    l *= r;
    return l;
  }

  template<class N>
  Vector2D<T>& operator/=(const N& r) {

    X /= r;
    Y /= r;

    return *this;
  }

  template<class N>
  friend Vector2D<T> operator/(Vector2D<T> l, const N& r) {
    l /= r;
    return l;
  }

  T DotProduct(const Vector2D<T>& r) const {
    return X * r.X + Y * r.Y;
  }

  Vector2D<T> Midpoint(const Vector2D<T>& r) const {
    return Vector2D<T>((X+r.X)/2, (Y+r.Y)/2);
  }

  // これが 0 のとき2つのベクトルは平行
  // （誤差を考え abs(perp) < eps という判定にした方が良い）
  T PerpProduct(const Vector2D<T>& r) const {
    return X * r.Y - Y * r.X;
  }

  static vector<Vector2D<T>> GetIntersectionOf2Lines(const Vector2D<T>& p1,
    const Vector2D<T>& v1, const Vector2D<T>& p2, const Vector2D<T>& v2,
    T eps = 1e-10) {

    T d = v1.PerpProduct(v2);

    if (Abs(d) < eps) {
      // 2つの線は平行

      // 重なっている場合は交点は存在することになるが、今回は省略
      return {};
    }

    auto w = p1 - p2;
    T si = v2.PerpProduct(w) / d;

    return { p1 + v1 * si };
  }
};

// 線分交差判定
// - 内部乗算で数値が大きくなるので、整数なら64bit型にするなど気を付けること
template <class T>
bool doesLineSegmentIntersect(T x1, T y1, T x2, T y2, T x3, T y3, T x4, T y4) {
  T tc = (x1 - x2) * (y3 - y1) + (y1 - y2) * (x1 - x3);
  T td = (x1 - x2) * (y4 - y1) + (y1 - y2) * (x1 - x4);
  T ta = (x3 - x4) * (y1 - y3) + (y3 - y4) * (x3 - x1);
  T tb = (x3 - x4) * (y2 - y3) + (y3 - y4) * (x3 - x2);
  return tc * td < 0 && ta * tb < 0;
}

template <class T>
struct Circle {
  T X = 0, Y = 0, R = 0;

  Circle(T x = 0, T y = 0, T r = 0) : X(x), Y(y), R(r) {}

  // 含むか
  bool DoesContain(const Vector2D<T>& p) const {
    T dx = p.X - X, dy = p.Y - Y;

    return dx * dx + dy * dy < R * R;
  }

  // 直線 ax+by+c との交点を取得する
  vector<Vector2D<T>> GetIntersectsWithLine(T a, T b, T c) const {
    T l = a * a + b * b;
    T k = a * X + b * Y + c;
    T d = l * R * R - k * k;
    if (d > 0) {
      T ds = sqrt(d);
      T apl = a / l, bpl = b / l;
      T xc = X - apl * k,yc = Y - bpl * k;
      T xd = bpl * ds, yd = apl * ds;
      return {
        {xc - xd, yc + yd},
        {xc + xd, yc - yd},
      };
    }
    else if (d == 0) {
      return { {X-a*k/l, Y-b*k/l} };
    }
    else {
      return {};
    }
  }

  // 交点の座標を求める
  // 0～2個。一方がもう一方を内包しているときは0個と判定される
  vector<Vector2D<T>> GetIntersects(const Circle<T>& r) const {

    // (x-a)^2+(y-b)^2 = r^2
    // (x-A)^2+(y-B)^2 = R^2

    // x^2 -2ax + a^2 + y^2 -2by + b^2 = r^2
    // 2Ax -2ax + a^2 - A^2 +2By -2by + b^2 - B^2 = r^2 - R^2
    // (2A-2a)x = (r+R)(r-R) - (a+A)(a-A) - (b+B)(b-B) - (2B-2b)y
    // x = ( (r+R)(r-R) + (A+a)(A-a) + (B+b)(B-b) + 2(b-B)y ) / (2A-2a)
    // ...
    // x = (By + c) / A
    // 
    T a = X - r.X, b = Y - r.Y;
    return GetIntersectsWithLine(a, b, 0.5 * ((R - r.R) * (R + r.R) - a * (X + r.X) - b * (Y + r.Y)));
  }

  // 与えられた複数の円のうち、最大でいくつが重なっているかを求める
  // 全て重なっていないとき 1
  // 多分 O(N^3)
  static int GetMaxIntersectCount(const vector<Circle<T>>& cs) {
    int result = 0;

    F0R(i, cs.size()) {
      int score;
      Vector2D<T> v;
      vector<Vector2D<T>> vs;

      // 中心点
      v = { cs[i].X, cs[i].Y };
      score = 1;
      F0R(j, cs.size()) {
        if (j == i) continue;
        if (cs[j].DoesContain(v)) score++;
      }
      chmax(result, score);

      // 交点
      FOR(j, i + 1, cs.size()) {
        vs = cs[i].GetIntersects(cs[j]);

        for (auto v : vs) {
          score = 2;
          F0R(k, cs.size()) {
            if (i == k || j == k) continue;
            if (cs[k].DoesContain(v)) score++;
          }
          chmax(result, score);
        }
      }
    }

    return result;
  }
};

// 与えられた点を全て内包する最小の凸多角形を求める
// - 凸包 (Convex Hull) というらしい
// - 多角形を作れない場合、要素数0～2のvectorを返す
//   与えられた点が3つ以上でも、直線上に並んでいる場合は要素数2が返る
template <class T>
vector<Vector2D<T>> GetConvexHull(const vector<Vector2D<T>>& pts) {
  if (pts.size() < 2) return pts;

  // 最初の2個追加
  // これに1点ずつ処理しながら追加していく
  vector<Vector2D<T>> conv(pts.begin(), pts.begin() + 2);

  FOR(i, 2, pts.size()) {
    auto pt = pts[i];

    // 辺に対して、外側にあるかどうか調べる
    int os = -1, oe = -1; // start index, end index
    int oc = 0; // count
    int oa = 0; // area. ヒットした区間が連続なら 1, 最初と最後で分かれているときは 2
    bool firstHit = true;
    F0R(j, conv.size()) {
      int k = j < conv.size() - 1 ? j + 1 : 0;
      auto v = conv[k] - conv[j];
      auto v2 = pt - conv[j];
      auto d = v.X * v2.Y - v.Y * v2.X;
      if (d > 0) {
        if (firstHit) {
          os = k;
          oa++;
          firstHit = false;
        }
        if (oa == 1) oe = k;
        oc++;
      }
      else {
        firstHit = true;
      }
    }

    if (oc == 1) {
      // 頂点を追加
      conv.insert(conv.begin() + os, pt);
    }
    else if (oc > 1) {
      // いくつかの頂点を消し、そこに挿入する
      conv.insert(conv.begin() + os, pt);
      if (os > oe) {
        conv.erase(conv.begin() + os + 1, conv.end());
        conv.erase(conv.begin(), conv.begin() + oe);
      }
      else {
        conv.erase(conv.begin() + os + 1, conv.begin() + oe + 1);
      }
    }
    else {
      if (conv.size() > 2) {
        // 内側or辺の上なので、何もしなくて良い
      }
      else {
        // まだ2点しかない、その線上なので、置き換えの可能性がある
        auto v = conv[1] - conv[0];
        auto v2 = pt - conv[0];

        if (v.X * v2.X + v.Y * v2.Y < 0) {
          // conv[0] を消す
          conv[0] = pt;
        }
        else if (v.MagnitudeSqr() < v2.MagnitudeSqr()) {
          conv[1] = pt;
        }
        else {
          // NOP
        }
      }
    }
  }

  return move(conv);
}

// 三角形の外心を求める
template <class T>
Vector2D<T> GetCircumcenterOfTriangle(const vector<Vector2D<T>>& pts) {

  if (pts.size() != 3) return Vector2D<T>();

  auto mp01 = pts[0].Midpoint(pts[1]);
  auto mp02 = pts[0].Midpoint(pts[2]);

  return Vector2D<T>::GetIntersectionOf2Lines(mp01, pts[2] - mp01, mp02, pts[1] - mp02)[0];
}

// 三角形の最小包含円を求める
template <class T>
Circle<T> GetBoundingCircleOfTriangle(const vector<Vector2D<T>>& pts) {
  
  if (pts.size() != 3) return Circle<T>();

  int l = -1, r;

  for (int i = 0, j = 1, k = 2; i < 3; i++, j++, k++) {
    if (j == 3) j = 0;
    else if (k == 3) k = 0;
    auto v = pts[j] - pts[i], v2 = pts[k] - pts[i];

    if (v.DotProduct(v2) <= 0) {
      l = j; r = k;
      break;
    }
  }

  if (l >= 0) {
    // Obtuse triangle
    // - 鈍角三角形は、鈍角の対辺の中点
    auto mp = pts[l].Midpoint(pts[r]);
    return Circle<T>(mp.X, mp.Y, pts[l].Distance(pts[r]) / 2);
  }
  else {
    // Acute triangle
    // - 鋭角三角形は、外心
    auto center = GetCircumcenterOfTriangle(pts);
    return Circle<T>(center.X, center.Y, center.Distance(pts[0]));
  }
}

// 与えられた点全てを内部または周上に含む円を求める
// - 最小包含円というらしい
// - 今回は凸包から導く方法にするが、他にも色々アルゴリズムがあるようだ
// https://en.wikipedia.org/wiki/Smallest-circle_problem
template <class T>
Circle<T> GetBoundingCircle(const vector<Vector2D<T>>& pts,
  T eps = 1e-10) {
  auto ch = GetConvexHull(pts);

  if (ch.size() == 0) return Circle<T>();
  else if (ch.size() == 1) return Circle<T>(ch[0].X, ch[0].Y);
  else if (ch.size() == 2) {
    auto cp = ch[0].Midpoint(ch[1]);
    return Circle<T>(cp.X, cp.Y, cp.Distance(ch[0]));
  }
  else if (ch.size() == 3) {
    return GetBoundingCircleOfTriangle(ch);
  }

  // ConvexHull の全ての3点の組み合わせに対し、最小包含円を求める
  // 他の全ての点も含む円だったら終了
  // O(N^4)

  vector<Vector2D<T>> tri(3);
  F0R(i, ch.size()) {
    tri[0] = ch[i];
    FOR(j, i + 1, ch.size()) {
      tri[1] = ch[j];
      F0R(k, j + 1, ch.size()) {
        tri[2] = ch[k];
        Circle<T> ci = GetBoundingCircleOfTriangle(tri);
        
        T r2 = (ci.R + eps) * (ci.R + eps);
#if 0
        cout << "Tri: ";
        for (auto v : tri) {
          cout << v.X << "," << v.Y << " ";
        }
        cout << newl;
        cout << "Cir: " << ci.X << ',' << ci.Y << " " << ci.R << newl;
#endif
        bool flag = true;

        F0R(l, ch.size()) {
          if (Vector2D<T>(ci.X, ci.Y).DistanceSqr(ch[l]) > r2) {
            flag = false;
            break;
          }
        }

        if (flag) {
          return ci;
        }
      }
    }
  }

  return Circle<T>();
}

// INSERT ABOVE HERE
signed main() {
  cin.tie(0);
  ios_base::sync_with_stdio(false);

#if 0
  vector<Vector2D<int>> pts = { {2,2},{2,3},{3,3},{3,2},{4,0} };
  auto conv = GetConvexIncludePoints(pts);
  for (auto v : conv) {
    cout << v.X << ',' << v.Y << newl;
  }
#endif
#if 0
  // Debug: Intersection
  Vector2D<double> p1 = { -5,2 }, p2 = { -2,3 }, p3 = { -1,-1 }, p4 = { -2,0 };
  auto vi = Vector2D<double>::GetIntersectionOf2Lines(
    p1, p2-p1, p3, p4-p3
  );
  cout << vi[0].X << ',' << vi[0].Y << newl;
#endif

  int N;
  cin >> N;
  vector<Vector2D<double>> ps(N);
  F0R(i, N) {
    cin >> ps[i].X >> ps[i].Y;
  }

  cout << std::fixed << std::setprecision(15);
  cout << (GetBoundingCircle(ps).R);
}
#endif


Compiler output:
a.cc:409:30: error: macro "F0R" passed 3 arguments, but takes just 2
  409 |       F0R(k, j + 1, ch.size()) {
      |                              ^
a.cc:19:9: note: macro "F0R" defined here
   19 | #define F0R(i,b) FOR(i,0,b)
      |         ^~~
a.cc: In function 'Circle<T> GetBoundingCircle(const std::vector<Vector2D<T> >&, T)':
a.cc:409:7: error: 'F0R' was not declared in this scope
  409 |       F0R(k, j + 1, ch.size()) {
      |       ^~~