UVa 12905 - Volume of Revolution

contents

  1. 1. Problem
  2. 2. Sample Input
  3. 3. Sample Output
  4. 4. Solution

Problem

給定一個方程式,接著繞 x 軸旋轉,計算區間 [l, r] 的體積。

考慮積分與數值積分的情況,計算兩者之間計算的誤差。其中會給定數值積分在 x 軸劃分的依準,以及繞行 x 軸轉換要切幾等分。

Sample Input

1
2
3
2
2 1 -4 5 1 4 4 3
1 1 0 1 4 4 3

Sample Output

1
2
Case 1: 27.9042
Case 2: 36.3380

Solution

這題最麻煩就是計算椎台體積

在幾何學中,錐台又稱平截頭體,指的是圓錐或稜錐被兩個平行平面所截後,位於兩個平行平面之間的立體。根據所截的是圓錐還是稜錐,可分為圓台與稜台。

參照 wiki Frustum

兩平行的上下底面積 S1, S2,根據高度 h,得到體積 V = (S1 + S2 + sqrt(S1 * S2)) /3 * h。之後就模擬劃分計算體積。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
using namespace std;
double P[32], Q[32];
const double pi = acos(-1);
#define eps 1e-6
void integral(double Q[]) {
for (int i = 31; i >= 1; i--)
Q[i] = Q[i-1] / (i);
Q[0] = 0;
}
double calcVal(double Q[], double x) {
double ret = 0;
for (int i = 31; i >= 0; i--)
ret = ret * x + Q[i];
return ret;
}
int main() {
int testcase, cases = 0;
int n, slices, stacks;
double a, b;
scanf("%d", &testcase);
while (testcase--) {
scanf("%d", &n);
memset(P, 0, sizeof(P));
memset(Q, 0, sizeof(Q));
for (int i = n; i >= 0; i--)
scanf("%lf", &P[i]);
scanf("%lf %lf", &a, &b);
scanf("%d %d", &slices, &stacks);
for (int i = 0; i <= n; i++)
for (int j = 0; j <= n; j++)
Q[i+j] += P[i] * P[j];
integral(Q);
double trueVal = (calcVal(Q, b) - calcVal(Q, a)) * pi;
double apprVal = 0;
double dx = (b - a) / stacks, dtheta = 2 * pi / slices;
for (double x = a; x + dx - eps <= b; x += dx) {
double x1 = x, x2 = x + dx, x12;
double fx1, fx2, S1, S2, fx12, S12;
fx1 = calcVal(P, x1);
fx2 = calcVal(P, x2);
S1 = fx1 * fx1 * sin(dtheta) /2;
S2 = fx2 * fx2 * sin(dtheta) /2;
apprVal += dx * (S1 + S2 + sqrt(S1 * S2)) /3 * slices;
}
printf("Case %d: %.4lf\n", ++cases, fabs(trueVal - apprVal) * 100 / trueVal);
}
return 0;
}
/*
2
2 1 -4 5 1 4 4 3
1 1 0 1 4 4 3
*/