#include
using namespace std;
#ifdef WIN32 #define randInt ((rand()«16)|rand()) #else #define randInt (rand()) #endif
const double eps = 1e-11; const double pi = acos(-1);
inline double sqr(const double& x) { return x * x; } inline int sgn(const double& x) { return (x > eps) - (x < -eps); }
typedef struct triobj { double x, y, z; triobj() {} triobj(const double& xo, const double& yo, const double& zo) { x = xo, y = yo, z = zo; } inline void read() { scanf("%lf%lf%lf", &x, &y, &z); } } point, vect; inline triobj operator +(const triobj& a, const triobj& b) { return triobj(a. x + b. x, a. y + b. y, a. z + b. z); } inline triobj operator -(const triobj& a, const triobj& b) { return triobj(a. x - b. x, a. y - b. y, a. z - b. z); } inline triobj operator *(const triobj& a, const triobj& b) { return triobj(a. y * b. z - a. z * b. y, a. z * b. x - a. x * b. z, a. x * b. y - a. y * b. x); } inline double operator &(const triobj& a, const triobj& b) { return a. x * b. x + a. y * b. y + a. z * b. z; } inline double vol(const point& a, const point& b, const point& c, const point& d) { return (a - b) & ((c - b) * (d - b)); } inline double sqLen(const vect& a) { return sqr(a. x) + sqr(a. y) + sqr(a. z); }
struct surface { int a, b, c; surface() {} surface(int ao, int bo, int co) { a = ao, b = bo, c = co; } };
const int maxn = 109; const int maxf = 10009;
int n, t, cu, mk[maxn][maxn]; point a[maxn]; surface h[maxf];
bool findQua() { t = 0; for (int i = 2; i < n; ++ i) { vect s((a[i] - a[0]) * (a[i] - a[1])); if (!sgn(sqLen(s))) continue; swap(a[i], a[2]); for (int j = i + 1; j < n; ++ j) { double v(vol(a[0], a[1], a[2], a[j])); if (sgn(v)) { swap(a[3], a[j]); h[t ++] = surface(0, 1, 2); h[t ++] = surface(0, 2, 1); return 1; } } } return 0; }
void addPoint(int ci) { static surface hn[maxf]; int tn(0); ++ cu; for (int i = 0; i < t; ++ i) { point u(a[h[i]. a]); point v(a[h[i]. b]); point w(a[h[i]. c]); if (sgn(vol(a[ci], u, v, w)) < 0) { mk[h[i]. a][h[i]. b] = mk[h[i]. b][h[i]. a] = cu; mk[h[i]. a][h[i]. c] = mk[h[i]. c][h[i]. a] = cu; mk[h[i]. c][h[i]. b] = mk[h[i]. b][h[i]. c] = cu; } else hn[tn ++] = h[i]; } t = tn; for (int i = 0; i < tn; ++ i) h[i] = hn[i]; for (int i = 0; i < tn; ++ i) { if (mk[hn[i]. a][hn[i]. b] == cu) h[t ++] = surface(hn[i]. b, hn[i]. a, ci); if (mk[hn[i]. b][hn[i]. c] == cu) h[t ++] = surface(hn[i]. c, hn[i]. b, ci); if (mk[hn[i]. c][hn[i]. a] == cu) h[t ++] = surface(hn[i]. a, hn[i]. c, ci); } }
double randDouble() { return (double)(randInt % 100000000) / 1e9; }
int main() { #ifndef ONLINE_JUDGE freopen(".in", “r”, stdin); #endif
srand(23472349);
scanf("%d", &n);
for (int i = 0; i < n; ++ i)
a[i]. read();
random_shuffle(a, a + n);
while (!findQua()) {
for (int i = 0; i < n; ++ i) {
a[i]. x += randDouble() / 1e7;
a[i]. y += randDouble() / 1e7;
a[i]. z += randDouble() / 1e7;
}
}
memset(mk, 0, sizeof(mk));
cu = 0;
for (int i = 3; i < n; ++ i)
addPoint(i);
double ans(0);
for (int i = 0; i < t; ++ i) {
vect v((a[h[i]. b] - a[h[i]. a]) * (a[h[i]. c] - a[h[i]. a]));
ans += sqrt(sqLen(v));
}
printf("%.6lf\n", ans * 0.5);
}