#include <bits/stdc++.h>

using namespace std;

using int64 = long long;
const int mod = 1e9 + 7;
// const int mod = 998244353;

const int64 infll = (1LL << 62) - 1;
const int inf = (1 << 30) - 1;

struct IoSetup {
  IoSetup() {
    cin.tie(nullptr);
    ios::sync_with_stdio(false);
    cout << fixed << setprecision(10);
    cerr << fixed << setprecision(10);
  }
} iosetup;


template< typename T1, typename T2 >
ostream &operator<<(ostream &os, const pair< T1, T2 > &p) {
  os << p.first << " " << p.second;
  return os;
}

template< typename T1, typename T2 >
istream &operator>>(istream &is, pair< T1, T2 > &p) {
  is >> p.first >> p.second;
  return is;
}

template< typename T >
ostream &operator<<(ostream &os, const vector< T > &v) {
  for(int i = 0; i < (int) v.size(); i++) {
    os << v[i] << (i + 1 != v.size() ? " " : "");
  }
  return os;
}

template< typename T >
istream &operator>>(istream &is, vector< T > &v) {
  for(T &in : v) is >> in;
  return is;
}

template< typename T1, typename T2 >
inline bool chmax(T1 &a, T2 b) { return a < b && (a = b, true); }

template< typename T1, typename T2 >
inline bool chmin(T1 &a, T2 b) { return a > b && (a = b, true); }

template< typename T = int64 >
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);
}

template< typename F >
struct FixPoint : F {
  FixPoint(F &&f) : F(forward< F >(f)) {}

  template< typename... Args >
  decltype(auto) operator()(Args &&... args) const {
    return F::operator()(*this, forward< Args >(args)...);
  }
};

template< typename F >
inline decltype(auto) MFP(F &&f) {
  return FixPoint< F >{forward< F >(f)};
}


struct Point final {

public:
  double x;
public:
  double y;


public:
  Point subtract(const Point &p) const;

public:
  double distance(const Point &p) const;

  // Signed area / determinant thing
public:
  double cross(const Point &p) const;

};


struct Circle final {

public:
  static const Circle INVALID;

private:
  static const double MULTIPLICATIVE_EPSILON;


public:
  Point c;   // Center
public:
  double r;  // Radius


public:
  bool contains(const Point &p) const;

public:
  bool contains(const std::vector< Point > &ps) const;

};


/*
 * (Main function) Returns the smallest circle that encloses all the given points.
 * Runs in expected O(n) time, randomized. Note: If 0 points are given, a circle of
 * negative radius is returned. If 1 point is given, a circle of radius 0 is returned.
 */
Circle makeSmallestEnclosingCircle(const std::vector< Point > &points);

// For unit tests
Circle makeDiameter(const Point &a, const Point &b);

Circle makeCircumcircle(const Point &a, const Point &b, const Point &c);

Point Point::subtract(const Point &p) const {
  return Point{x - p.x, y - p.y};
}


double Point::distance(const Point &p) const {
  return std::hypot(x - p.x, y - p.y);
}


double Point::cross(const Point &p) const {
  return x * p.y - y * p.x;
}


/*---- Members of struct Circle ----*/

const Circle Circle::INVALID{Point{0, 0}, -1};

const double Circle::MULTIPLICATIVE_EPSILON = 1 + 1e-14;


bool Circle::contains(const Point &p) const {
  return c.distance(p) <= r * MULTIPLICATIVE_EPSILON;
}


bool Circle::contains(const vector< Point > &ps) const {
  for(const Point &p : ps) {
    if(!contains(p))
      return false;
  }
  return true;
}


/*---- Smallest enclosing circle algorithm ----*/

static Circle makeSmallestEnclosingCircleOnePoint(const vector< Point > &points, size_t end, const Point &p);

static Circle makeSmallestEnclosingCircleTwoPoints(const vector< Point > &points, size_t end, const Point &p, const Point &q);

static std::default_random_engine randGen((std::random_device()) ());


// Initially: No boundary points known
Circle makeSmallestEnclosingCircle(const vector< Point > &points) {
  // Clone list to preserve the caller's data, randomize order
  vector< Point > shuffled = points;
  std::shuffle(shuffled.begin(), shuffled.end(), randGen);

  // Progressively add points to circle or recompute circle
  Circle c = Circle::INVALID;
  for(size_t i = 0; i < shuffled.size(); i++) {
    const Point &p = shuffled.at(i);
    if(c.r < 0 || !c.contains(p))
      c = makeSmallestEnclosingCircleOnePoint(shuffled, i + 1, p);
  }
  return c;
}


// One boundary point known
static Circle makeSmallestEnclosingCircleOnePoint(const vector< Point > &points, size_t end, const Point &p) {
  Circle c{p, 0};
  for(size_t i = 0; i < end; i++) {
    const Point &q = points.at(i);
    if(!c.contains(q)) {
      if(c.r == 0)
        c = makeDiameter(p, q);
      else
        c = makeSmallestEnclosingCircleTwoPoints(points, i + 1, p, q);
    }
  }
  return c;
}


// Two boundary points known
static Circle makeSmallestEnclosingCircleTwoPoints(const vector< Point > &points, size_t end, const Point &p, const Point &q) {
  Circle circ = makeDiameter(p, q);
  Circle left = Circle::INVALID;
  Circle right = Circle::INVALID;

  // For each point not in the two-point circle
  Point pq = q.subtract(p);
  for(size_t i = 0; i < end; i++) {
    const Point &r = points.at(i);
    if(circ.contains(r))
      continue;

    // Form a circumcircle and classify it on left or right side
    double cross = pq.cross(r.subtract(p));
    Circle c = makeCircumcircle(p, q, r);
    if(c.r < 0)
      continue;
    else if(cross > 0 && (left.r < 0 || pq.cross(c.c.subtract(p)) > pq.cross(left.c.subtract(p))))
      left = c;
    else if(cross < 0 && (right.r < 0 || pq.cross(c.c.subtract(p)) < pq.cross(right.c.subtract(p))))
      right = c;
  }

  // Select which circle to return
  if(left.r < 0 && right.r < 0)
    return circ;
  else if(left.r < 0)
    return right;
  else if(right.r < 0)
    return left;
  else
    return left.r <= right.r ? left : right;
}


Circle makeDiameter(const Point &a, const Point &b) {
  Point c{(a.x + b.x) / 2, (a.y + b.y) / 2};
  return Circle{c, max(c.distance(a), c.distance(b))};
}


Circle makeCircumcircle(const Point &a, const Point &b, const Point &c) {
  // Mathematical algorithm from Wikipedia: Circumscribed circle
  double ox = (min(min(a.x, b.x), c.x) + max(min(a.x, b.x), c.x)) / 2;
  double oy = (min(min(a.y, b.y), c.y) + max(min(a.y, b.y), c.y)) / 2;
  double ax = a.x - ox, ay = a.y - oy;
  double bx = b.x - ox, by = b.y - oy;
  double cx = c.x - ox, cy = c.y - oy;
  double d = (ax * (by - cy) + bx * (cy - ay) + cx * (ay - by)) * 2;
  if(d == 0)
    return Circle::INVALID;
  double x = ((ax * ax + ay * ay) * (by - cy) + (bx * bx + by * by) * (cy - ay) + (cx * cx + cy * cy) * (ay - by)) / d;
  double y = ((ax * ax + ay * ay) * (cx - bx) + (bx * bx + by * by) * (ax - cx) + (cx * cx + cy * cy) * (bx - ax)) / d;
  Point p{ox + x, oy + y};
  double r = max(max(p.distance(a), p.distance(b)), p.distance(c));
  return Circle{p, r};
}

int main() {
  int N;
  cin >> N;
  vector< Point > P(N);
  for(int i = 0; i < N; i++) {
    cin >> P[i].x >> P[i].y;
  }
  cout << makeSmallestEnclosingCircle(P).r << endl;
}


Measured memory_bytes: 256