把所有的点都映射到XOZ这个平面的第一象限内,则这个三维问题可以转化二维问题:
求一条直线,使所有点在这条直线的下方,直线与X轴和Z轴围成的三角形旋转形成的圆锥体积最小。
这样转化之后可以看出直线的临界条件应当是经过其中一点。
三分圆锥半径R,因为要覆盖所有的点,让点(R, 0)与所有点连线,直线与Z轴交点即为H,H取其中最大的那个。
1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cmath> 5 #include <algorithm> 6 7 #define EPS 1e-9 8 9 using namespace std; 10 11 const int MAXN = 10010; 12 const double PI = acos(-1.0); 13 14 struct point 15 { 16 double x, y; 17 }; 18 19 int N; 20 point P[MAXN]; 21 22 int dcmp( double a ) 23 { 24 if ( fabs(a) < EPS ) return 0; 25 return a < 0 ? -1 : 1; 26 } 27 28 double GetH( double R ) 29 { 30 double maxH = 0.0; 31 for ( int i = 0; i < N; ++i ) 32 { 33 double tmp = R * P[i].y / ( R - P[i].x ); 34 if ( dcmp( tmp - maxH ) > 0 ) maxH = tmp; 35 } 36 return maxH; 37 } 38 39 int main() 40 { 41 while ( ~scanf( "%d", &N ) ) 42 { 43 double maxR = 0.0; 44 for ( int i = 0; i < N; ++i ) 45 { 46 double x, y, z; 47 scanf( "%lf%lf%lf", &x, &y, &z ); 48 P[i].x = sqrt( x*x + y*y ); 49 P[i].y = z; 50 maxR = max( maxR, P[i].x ); 51 } 52 53 double low = maxR, high = 1e10; 54 55 while ( dcmp( high - low ) > 0 ) 56 { 57 double mid = ( low + high ) / 2.0; 58 double midmid = ( mid + high ) / 2.0; 59 60 double midV = GetH( mid ) * mid * mid; 61 double midmidV = GetH( midmid ) * midmid * midmid; 62 63 if ( dcmp( midV - midmidV ) <= 0 ) high = midmid; 64 else low = mid; 65 } 66 67 printf("%.3f %.3f ", GetH(low), low ); 68 } 69 return 0; 70 }