// Tetrahedron #include #include #include #include using namespace std; /***************************************************************************** * メイン *****************************************************************************/ /** * 指定された 3 辺の長さを持つ三角形がつくれるかどうか判定する。 * * @param a 辺の長さ * @param b 辺の長さ * @param c 辺の長さ * @return {a, b, c} を長さとするような辺を持つ三角形が作れるなら true。 */ static inline bool check_triangle(int a, int b, int c) { // sort if(a < b) swap(a, b); if(a < c) swap(a, c); if(b < c) swap(b, c); // 一番長い辺が他の 2 辺の和より短ければよい。(はず return a < (b + c); } /** * 三角形の頂点から底辺への垂線の足の位置を求める。 * * @param base 底辺の長さ * @param a 求める側の斜辺の長さ * @param b 残りの斜辺の長さ * @return 底辺上に垂直に投影された a の長さ。 */ static inline double tri_foot(const double base, const double a, const double b) { /* * 底面を (0,0), (a,0), (x0,y0) におくとすると、 * |~ x0 = (a * a + b * b - c * c) / 2a * |_ y0 = ±sqrt(b * b - x * x) */ return (base * base + a * a - b * b) / (2 * base); } /** * 指定された辺の長さを持つ四面体の体積を求める。 * * @param a 底面の辺の長さ * @param b 底面の辺の長さ * @param c 底面の辺の長さ * @param l1 c と a の間にある斜辺の長さ * @param l2 a と b の間にある斜辺の長さ * @param l3 b と c の間にある斜辺の長さ * @return 体積 */ static inline double tetrahedron(const double a, const double b, const double c, const double l1, const double l2, const double l3) { // 底面の頂点位置 const double x0 = tri_foot(a, b, c), y0 = sqrt(b * b - x0 * x0); // 底面に頂点から垂線を下ろした時の位置 (x1, y1) を求める const double coeff = tri_foot(b, l2, l3) / b; const double x1 = tri_foot(a, l2, l1), y1 = coeff * y0 - x0 / y0 * (x1 - coeff * x0); #ifdef _DEBUG cerr << "Bottom Surface : (0, 0), (" << a << ", 0), (" << x0 << ", " << y0 << ")" << endl; cerr << "Projected Top at (" << x1 << ", " << y1 << ")" << endl; #endif//_DEBUG // 底面の面積 (ヘロンの公式) const double s = (a + b + c) / 2.0; const double area = sqrt(s * (s - a) * (s - b) * (s - c)); // 四面体の高さ if(l2 * l2 <= x1 * x1 + y1 * y1) return -1.0; // could not form const double h = sqrt(l2 * l2 - (x1 * x1 + y1 * y1)); // 錐体の体積 (公式) const double v = area * h / 3.0; #ifdef _DEBUG cerr << "Area of the bottom surface = " << area << endl; cerr << "Height of the polyhedron = " << h << endl; cerr << "=>Volume of the polyhedron = " << v << endl; #endif//_DEBUG return v; } /** * 問題を解く。 * * @param prob 辺の長さの集合 * @return できる立体の体積の最大値 */ double solve(const vector& prob) { double volume = 0.0; vector used(prob.size(), false); // 底面を選択 (not permutation, but combination) for(int i1 = 0; i1 < prob.size(); i1++) for(int i2 = i1 + 1; i2 < prob.size(); i2++) for(int i3 = i2 + 1; i3 < prob.size(); i3++) { if(! check_triangle(prob[i1], prob[i2], prob[i3])) continue; used[i1] = used[i2] = used[i3] = true; // 立ち上がり線を選択 (permutation) for(int h1 = 0; h1 < prob.size(); h1++) { if(used[h1]) continue; used[h1] = true; for(int h2 = 0; h2 < prob.size(); h2++) { if(used[h2]) continue; used[h2] = true; for(int h3 = 0; h3 < prob.size(); h3++) { if(used[h3]) continue; #ifdef _DEBUG cerr << "Bottom " << i1 << ", " << i2 << ", " << i3 << endl; cerr << "Rising " << h1 << ", " << h2 << ", " << h3 << endl; #endif//_DEBUG // ちゃんと面ができるかチェック if(! check_triangle(prob[i1], prob[h1], prob[h2]) || ! check_triangle(prob[i2], prob[h2], prob[h3]) || ! check_triangle(prob[i3], prob[h3], prob[h1])) { #ifdef _DEBUG cerr << "!! Could not form a tetrahedron." << endl; #endif//_DEBUG continue; } // 求積 const double v = tetrahedron(prob[i1], prob[i2], prob[i3], prob[h1], prob[h2], prob[h3]); if(v > volume) volume = v; } used[h2] = false; } used[h1] = false; } used[i1] = used[i2] = used[i3] = false; } return volume; } /** * メインルーチン */ int main() { int N; while(cin >> N, N) { vector prob; while(N-- > 0) { int a; cin >> a; prob.push_back(a); } static char buffer[4096]; snprintf(buffer, sizeof buffer, "%.10lf", solve(prob)); cout << buffer << endl; } return 0; }