题意:给出空间内一些Z>0的点,保证有点不在Z轴上,求一个体积最小的包含所有点的圆锥,输出其h和r。
思路:基本所有人都能想到二维化,问题就转化成了在第一象限内有一些y>0的点,用一条斜率<0的直线覆盖它们。很容易证明最优解的直线应该过其中一个或两个点,再推算一下可以得出,过点(x,y)的最优解为r = 1.5x,h = 3y,越接近它V越小。这样问题就简单明了了,先做一个凸包,再找出上凸包中斜率<0的边所过的点,枚举这些点的最优解就行了。
做这题时WA了好几发,害得我以为是精度问题,后来才知道,是INF开小了(╯' - ')╯ ┻━┻ (掀桌子)。于是我把所有涉及精度的部分全还原了┬—┬ ノ( ' - 'ノ) (摆好摆好),发现跑出来时间还是242ms,(╯°Д°)╯ ┻━┻(再他妈的掀一次)。
1 #include <cstdio> 2 #include <cmath> 3 #include <algorithm> 4 using namespace std; 5 #define N 10010 6 struct Point{ 7 double x, y; 8 Point(double _x = 0, double _y = 0):x(_x), y(_y){} 9 Point operator-(const Point &P)const{ return Point(x-P.x, y-P.y); } 10 bool operator< (const Point &p)const{ return (x<p.x||(x==p.x&&y<p.y)); } 11 }; 12 double Cross(const Point &A, const Point &B){ return A.x*B.y-A.y*B.x; } 13 Point p[N],ch[N]; 14 double a[N]; 15 double getx(Point A, Point B){ 16 return (A.x*B.y-B.x*A.y)/(B.y-A.y); 17 } 18 double gety(Point A, Point B){ 19 return (A.x*B.y-B.x*A.y)/(A.x-B.x); 20 } 21 int main(){ 22 int n,m,k,i; 23 double x,y,z; 24 while(~scanf("%d",&n)){ 25 for(i = 0; i < n; i++){ 26 scanf("%lf%lf%lf",&x,&y,&z); 27 p[i].x = sqrt(x*x+y*y); 28 p[i].y = z; 29 } 30 sort(p,p+n); 31 m = 0; 32 for(i = 0; i < n; i++){ 33 while(m>1 && Cross(ch[m-1]-ch[m-2],p[i]-ch[m-2]) <= 0) m--; 34 ch[m++] = p[i]; 35 } 36 k = m; 37 for(i = n-2; i >= 0; i--){ 38 while(m>k && Cross(ch[m-1]-ch[m-2],p[i]-ch[m-2]) <= 0) m--; 39 ch[m++] = p[i]; 40 } 41 if(n > 1) m--; 42 ch[m] = ch[0]; 43 double Min,r,h,R,H; 44 Min = 8000000000000000000.0; a[k-1] = ch[k-1].x; 45 for(i = k; i <= m; i++){ 46 if(ch[i].y <= ch[i-1].y) break; 47 a[i] = getx(ch[i],ch[i-1]); 48 if(1.5*ch[i-1].x < a[i-1]) 49 r = a[i-1], h = gety(ch[i-1],Point(r,0)); 50 else if(1.5*ch[i-1].x <= a[i]) 51 r = 1.5*ch[i-1].x, h = 3*ch[i-1].y; 52 else r = a[i], h = gety(ch[i-1],Point(r,0)); 53 if(r*r*h < Min){ 54 Min = r*r*h; 55 R = r; H = h; 56 } 57 } 58 if(1.5*ch[i-1].x < a[i-1]) 59 r = a[i-1], h = gety(ch[i-1],Point(r,0)); 60 else r = 1.5*ch[i-1].x, h = 3*ch[i-1].y; 61 if(r*r*h < Min){ 62 R = r; H = h; 63 } 64 printf("%.3lf %.3lf\n",H,R); 65 } 66 return 0; 67 }