/* Bismillahirrahmanirrahim */
/* Author : Jehian Norman Saviero (@Reiva5) */
#include <bits/stdc++.h>
 
// MACROS SAMPAH
#define Jehian using
#define Norman namespace
#define Saviero std
 
Jehian Norman Saviero;
 
// MACROS TYPE
typedef long l;
typedef long long ll;
typedef unsigned long ul;
typedef unsigned long long ull;
typedef long double ld;
typedef pair<int,int> pi;
typedef pair<l,l> pl;
typedef pair<ll,ll> pll;
typedef vector<int> vi;
typedef vector<l> vl;
typedef vector<ll> vll;
 
// MACROS FOR PRINT
#define nl printf("\n")
 
// MACROS FOR ATTRIBUTE
#define fi first
#define se second
 
// MACROS FOR FUNCTION AND METHOD
#define eb emplace_back
#define mp make_pair
#define pb push_back
#define pf push_front
#define ppb pop_back
#define ppf pop_front
#define ALL(x) (x).begin(), (x).end()
#define ALLN(x,n) (x), (x)+(n)
#define CUBE(x) (SQR(x)*(x))
#define SET(x,y) for (int _qwe = sizeof(x)/sizeof(x[0]); _qwe; ) x[--_qwe] = (y)
#define SQR(x) ((x)*(x))
#define SSORT(x,sz) sort(ALLN(x,sz))
#define RESET(x) memset((x), 0, sizeof(x))
#define VSORT(x) sort(ALL(x))
 
// MACROS READ INPUT
#define sci(x) scanf("%d", &x)
#define scl(x) scanf("%d", &x)
#define scll(x) scanf("%ld", &x)
#define scd(x) scanf("%lf", &x)
#define scdouble(x) scanf("%Lf", &x)
#define scul(x) scl(x)
#define scull(x) scll(x)

#define MAX_SIZE 1000
const double PI = 2.0*acos(0.0);
const double EPS = 1e-9; //too small/big?????
struct PT {
	double x,y;
	double length() { return sqrt(x*x+y*y); }
	// normalize the vector to unit length; return -1 if the vector is 0
	int normalize() {
		double l = length();
		if(fabs(l)<EPS) return -1;
		x/=l; y/=l;
		return 0;
	}
	PT operator-(PT a) {
		PT r;
		r.x=x-a.x; r.y=y-a.y;
		return r;
	}
	PT operator+(PT a) {
		PT r;
		r.x=x+a.x; r.y=y+a.y;
		return r;
	}
	PT operator*(double sc) {
		PT r;
		r.x=x*sc; r.y=y*sc;
		return r;
	}
};
bool operator<(const PT& a,const PT& b) {
	if (fabs(a.x-b.x) < EPS) return a.y<b.y;
	return a.x<b.x;
}
// the distance between two points
double dist(PT& a, PT& b) {
	return sqrt((a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y));
}
// the inner product of two vectors
double dot(PT& a, PT& b){
	return (a.x * b.x + a.y * b.y);
}
// =================================================================
// The Convex Hull
// =================================================================
// which side is p3 to the line p1->p2? returns: 1 left, 0 on, -1 right
int sideSign(PT& p1,PT& p2,PT& p3) {
	double sg = (p1.x-p3.x)*(p2.y-p3.y)-(p1.y - p3.y)*(p2.x-p3.x);
	if (fabs(sg)<EPS) return 0;
	if (sg>0) return 1;
	return -1;
}
// used by convec hull: from p3, if p1 is better than p2
bool better(PT& p1,PT& p2,PT& p3) {
	double sg = (p1.y - p3.y)*(p2.x-p3.x)-(p1.x-p3.x)*(p2.y-p3.y);
	//watch range of the numbers
	if (fabs(sg)<EPS) {
		if (dist(p3,p1)>dist(p3,p2)) return true;
		else return false;
	}
	if (sg<0) return true;
	return false;
}
//convex hull nlogn
// vin is not pass by reference, since we will rotate it
void vex2(vector<PT> vin, vector<PT>& vout) {
	vout.clear();
	int n=vin.size();
	sort(vin.begin(),vin.end());
	PT stk[MAX_SIZE];
	int pstk, i;
	
	// hopefully more than 2 points
	stk[0] = vin[0];
	stk[1] = vin[1];
	pstk = 2;
	for (i = 2; i < n; i++) {
		if (dist(vin[i], vin[i-1])<EPS) continue;
		while (pstk > 1 && better(vin[i], stk[pstk-1], stk[pstk-2])) pstk--;
		stk[pstk] = vin[i];
		pstk++;
	}
	for(i=0; i<pstk; i++) vout.push_back(stk[i]);
	// turn 180 degree
	for(i=0; i<n; i++) {
		vin[i].y = -vin[i].y;
		vin[i].x = -vin[i].x;
	}
	sort(vin.begin(), vin.end());
	stk[0] = vin[0];
	stk[1] = vin[1];
	pstk = 2;
	for(i = 2; i< n; i++) {
		if (dist(vin[i], vin[i-1])<EPS) continue;
		while(pstk > 1 && better(vin[i], stk[pstk-1], stk[pstk-2])) pstk--;
		stk[pstk] = vin[i];
		pstk++;
	}
	for(i = 1; i < pstk-1; i++) {
		stk[i].x= -stk[i].x; // don’t forget rotate 180 d back.
		stk[i].y= -stk[i].y;
		vout.push_back(stk[i]);
	}
}
// test whether a simple polygon is convex
// return 0 if not convex, 1 if strictly convex,
// 2 if convex but there are points unnecesary
// this function does not work if the polycon is self intersecting
// in that case, compute the convex hull of v, and see if both have the same area
int isConvex(vector<PT>& v) {
	int i,j,k;
	int c1=0; int c2=0; int c0=0;
	int n=v.size();
	for (i = 0; i < n; i++) {
		j=(i+1)%n;
		k=(j+1)%n;
		int s=sideSign(v[i], v[j], v[k]);
		if(s==0) c0++;
		if(s>0) c1++;
		if(s<0) c2++;
	}
	if(c1 && c2) return 0;
	if(c0) return 2;
	return 1;
}
// ===============================================================
// Areas
// ===============================================================
double trap(PT a, PT b) {
	return (0.5*(b.x - a.x)*(b.y + a.y));
}

// Area of a simple polygon, not neccessary convex
double area(vector<PT> &vin) {
	int n = vin.size();
	double ret = 0.0;
	for(int i = 0; i < n; i++)
	ret += trap(vin[i], vin[(i+1)%n]);
	return fabs(ret);
}

// Perimeter of a simple polygon, not neccessary convex
double peri(vector<PT> &vin) {
	int n = vin.size();
	double ret = 0.0;
	for (int i = 0; i < n; i++)
	ret += dist(vin[i], vin[(i+1)%n]);
	return ret;
}
double triarea(PT a, PT b, PT c) {
	return fabs(trap(a,b)+trap(b,c)+trap(c,a));
}
// height from a to the line bc
double height(PT a, PT b, PT c) {
	double s3 = dist(c, b);
	double ar = triarea(a,b,c);
	return (2.0*ar/s3);
}
// ====================================================
// Points and Lines
// ====================================================

// two lines given by p1->p2, p3->p4 r is the intersection point
// return -1 if two lines are parallel
int intersection( PT p1, PT p2, PT p3, PT p4, PT &r ) {
	double d = (p4.y - p3.y)*(p2.x-p1.x) - (p4.x - p3.x)*(p2.y - p1.y);
	if( fabs( d ) < EPS ) return -1;
	// might need to do something special!!!
	double ua, ub;
	ua = (p4.x - p3.x)*(p1.y-p3.y) - (p4.y-p3.y)*(p1.x-p3.x);
	ua /= d;
	// ub = (p2.x - p1.x)*(p1.y-p3.y) - (p2.y-p1.y)*(p1.x-p3.x);
	//ub /= d;
	r = p1 + (p2-p1)*ua;
	return 0;
}
// the closest point on the line p1->p2 to p3
void closestpt( PT p1, PT p2, PT p3, PT &r ) {
	if( fabs( triarea( p1, p2, p3 ) ) < EPS )
	{ r = p3; return; }
	PT v = p2-p1;
	v.normalize();
	double pr; // inner product
	pr = (p3.y-p1.y)*v.y + (p3.x-p1.x)*v.x;
	r = p1+v*pr;
}

// point generated by altitudes
int hcenter( PT p1, PT p2, PT p3, PT& r ) {
	if( triarea( p1, p2, p3 ) < EPS ) return -1;
	PT a1, a2;
	closestpt( p2, p3, p1, a1 );
	closestpt( p1, p3, p2, a2 );
	intersection( p1, a1, p2, a2, r );
	return 0;
}

int center( PT p1, PT p2, PT p3, PT& r ) {
	// point generated by circumscribed circle
	if( triarea( p1, p2, p3 ) < EPS ) return -1;
	PT a1, a2, b1, b2;
	a1 = (p2+p3)*0.5;
	a2 = (p1+p3)*0.5;
	b1.x = a1.x - (p3.y-p2.y);
	b1.y = a1.y + (p3.x-p2.x);
	b2.x = a2.x - (p3.y-p1.y);
	b2.y = a2.y + (p3.x-p1.x);
	intersection( a1, b1, a2, b2, r );
	return 0;
}

int main() {
	int N;
	sci(N);
	PT dat[N];
	for (int i = 0; i < N; ++i) {
		cin >> dat[i].x >> dat[i].y;
	}
	double ans = 1e9;
	for (int i = 0; i < N; ++i) {
		for (int j = 0; j < N; ++j) {
			if (i == j) continue;
			PT r = {(dat[i].x + dat[j].x)/2, (dat[i].y + dat[j].y)/2};
			double R = dist(dat[i], r);
			bool valid = 1;
			for (int m = 0; m < N && valid; ++m) {
				valid = dist(dat[m], r) <= R + EPS;
			}
			if (valid) ans = min(ans, R);
		}
	}
	for (int i = 0; i < N; ++i) {
		for (int j = 0; j < N; ++j) {
			for (int k = 0; k < N; ++k) {
				if (i == j || j == k || k == i) continue;
				PT r;
				double AB, BC, CA;
				AB = dist(dat[i], dat[j]);
				BC = dist(dat[j], dat[k]);
				CA = dist(dat[k], dat[i]);
				double R = (AB * BC * CA)/((double) 4 * triarea(dat[i], dat[j], dat[k]));
				if (center(dat[i], dat[j], dat[k], r)) continue;
				bool valid = 1;
				for (int m = 0; m < N && valid; ++m) {
					valid = dist(dat[m], r) <= R + EPS;
				}
				if (valid) ans = min(ans, R);
			}
		}
	}
	cout << setprecision(9) << fixed << ans << '\n';
	return 0;
}

Measured memory_bytes: 256