//模擬退火
#include <iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
const double eps=1e-8;
struct point3D
{
double x,y,z;
} data[105];
int n;
double dis(point3D a,point3D b)
{
return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)+(a.z-b.z)*(a.z-b.z));
}
double solve()
{
double step=10000,ans=1e30,mt;
point3D z;
z.x=z.y=z.z=0;
int s=0;
while(step>eps)
{
for(int i=0; i<n; i++)
if(dis(z,data[s])<dis(z,data[i])) s=i;
mt=dis(z,data[s]);
ans=min(ans,mt);
z.x+=(data[s].x-z.x)/mt*step;
z.y+=(data[s].y-z.y)/mt*step;
z.z+=(data[s].z-z.z)/mt*step;
step*=0.98;
}
return ans;
}
int main()
{
double ans;
while(scanf("%d",&n)!=EOF)
{
for(int i=0; i<n; i++)
scanf("%lf%lf%lf",&data[i].x,&data[i].y,&data[i].z);
ans=solve();
printf("%.7f\n",ans);
}
return 0;
}
//三分
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e2+5;
const double eps=1e-7;
typedef struct {double p[3];}point;
point a[maxn];
int n;
double cal(point now)
{
double ans=0.0;
for(int i=0;i<n;i++)
ans=max(ans,sqrt((a[i].p[0]-now.p[0])*(a[i].p[0]-now.p[0])+(a[i].p[1]-now.p[1])*(a[i].p[1]-now.p[1])+(a[i].p[2]-now.p[2])*(a[i].p[2]-now.p[2])));
return ans;
}
point del(point now,int cnt)
{
if(cnt>=3)
return now;
double r=100000,l=-100000;
double dr,dl;
point tp1,tp2,ans1,ans2,ans;
tp1=tp2=ans=now;
while(r-l>eps)
{
dr=(2*r+l)/3;
dl=(2*l+r)/3;
tp1.p[cnt]=dl;
tp2.p[cnt]=dr;
ans1=del(tp1,cnt+1);
ans2=del(tp2,cnt+1);
if(cal(ans1)>cal(ans2))
{
l=dl;
ans=ans1;
}
else
{
r=dr;
ans=ans2;
}
}
return ans;
}
int main()
{
while(scanf("%d",&n)!=EOF)
{
for(int i=0;i<n;i++)
scanf("%lf%lf%lf",&a[i].p[0],&a[i].p[1],&a[i].p[2]);
point ans;
printf("%lf\n",cal(del(ans,0)));
}
return 0;
}
/*
3
0 0 0
3 0 0
0 4 0
4
0 0 0
1 0 0
0 1 0
0 0 1
5
0 1 2
2 3 4
5 6 7
7 8 9
9 2 3
*/