[HDU3756]Dome of Circus

题目大意:
  在一个立体的空间内有n个点(x,y,z),满足z>=0。
  现在要你放一个体积尽量小的圆锥,把这些点都包住。
  求圆锥的高和底面半径。

思路:
  因为圆锥里面是对称的,因此问题很容易可以转化到一个二维平面上,我们只需要将所有点绕着z轴旋转到xOz平面上即可。
  考虑不同半径时圆锥的体积,不难发现这是一个关于半径r的下凸函数。
  于是我们可以三分求解。
  对于当前分出来的两个半径,我们可以O(n)枚举每个点算出高度,然后看一下哪边体积小就继续分哪边。

 1 #include<cmath>
 2 #include<cstdio>
 3 #include<cctype>
 4 #include<algorithm>
 5 inline int getint() {
 6     register char ch;
 7     while(!isdigit(ch=getchar()));
 8     register int x=ch^'0';
 9     while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
10     return x;
11 }
12 const double eps=5e-5;
13 const int N=10001;
14 struct Point {
15     double x,y;
16 };
17 Point p[N];
18 inline double sqr(const double &x) {
19     return x*x;
20 }
21 int n;
22 inline double calc(const double &r) {
23     double h=0;
24     for(register int i=0;i<n;i++) {
25         h=std::max(h,(r*p[i].y)/(r-p[i].x));
26     }
27     return h;
28 }
29 int main() {
30     for(register int T=getint();T;T--) {
31         n=getint();
32         double l=0,r=1e4;
33         for(register int i=0;i<n;i++) {
34             double x,y,z;
35             scanf("%lf%lf%lf",&x,&y,&z);
36             p[i]=(Point){sqrt(sqr(x)+sqr(y)),z};
37             l=std::max(l,p[i].x);
38         }
39         while(r-l>eps) {
40             const double mid1=(l*2+r)/3,mid2=(l+r*2)/3;
41             if(calc(mid1)*sqr(mid1)<calc(mid2)*sqr(mid2)) {
42                 r=mid2;
43             } else {
44                 l=mid1;
45             }
46         }
47         const double ans=(l+r)/2;
48         printf("%.3f %.3f\n",calc(ans),ans);
49     }
50     return 0;
51 }

 

posted @ 2017-10-31 09:05  skylee03  阅读(86)  评论(0编辑  收藏  举报