【題意】:在三維空間中,給出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 }