【题意】:在三维空间中,给出n个点(x,y,z) (z>=0),要求用一个体积最小的圆锥包围所有的点,输出该圆锥的高和半径。
【题解】:可以先分析一下,当这个圆锥的高很大时,圆锥的体积非常大;当这个圆锥的高太小的时候,圆锥的半径就会非常大,此时圆锥的体积还是很大。
于是我们可以得出一个结论,圆锥的高不能太小也不能太大。
这里有一步预处理,就是把空间直角坐标系转换为柱面坐标系。(x,y,z) => (sqrt(x*x+y*y),z);
有了上面的结论,我们就可以利用三分极值来确定这个高的最优值,然后通过相似三角形就可以求出圆锥的半径。
此题也可以通过三分半径来求解。
【代码】:
1 #include "iostream"
2 #include "cstdio"
3 #include "cstring"
4 #include "cmath"
5 using namespace std;
6 #define maxn 10500
7 #define eps 1e-8
8 #define pi 3.1415926535897932384626433832795
9 int n;
10 double rr;
11 struct Point {
12 double x, y, r, z;
13 Point(){}
14 Point(double _x, double _y, double _z) {
15 x = _x, y = _y, z = _z, r = sqrt(_x * _x + _y * _y) ;
16 }
17 }point[maxn];
18
19 double work(double h) {
20 double tmp;
21 rr = 0.0;
22 for(int i = 0; i < n; i++) {
23 double r = point[i].r, z = point[i].z;
24 double tmp = h * r / (h - z);
25 rr = max(rr, tmp);
26 }
27 double area = pi * rr * rr * h / 3.0;
28 return area;
29 }
30
31 void solve(double res) {
32 double low = res, high = 10000000, mid, mmid, ansh, ansr;
33 while(low + eps < high) {
34 mid = (low + high) / 2.0;
35 mmid = (mid + high) / 2.0;
36 if(work(mid) < work(mmid)) {
37 high = mmid;
38 ansh = mid;
39 } else {
40 low = mid;
41 ansh = mmid;
42 }
43 ansr = rr;
44 }
45 printf("%.3f %.3f\n", ansh, ansr);
46
47 }
48
49 int main() {
50 int T;
51 double x, y, z;
52 scanf("%d", &T);
53 while(T--) {
54 scanf("%d", &n);
55 double low = 0.0;
56 for(int i = 0; i < n; i++) {
57 scanf("%lf%lf%lf", &x, &y, &z);
58 point[i] = Point(x, y, z);
59 low = max(low, z);
60 }
61 solve(low);
62 }
63 return 0;
64 }