【题目】
CSP-S 2021 提高级 第一轮(初赛) 阅读程序(1)
01 #include <iostream>
02 #include <cmath>
03 using namespace std;
04
05 const double r = acos(0.5);
06
07 int a1, b1, c1, d1;
08 int a2, b2, c2, d2;
09
10 inline int sq(const int x) { return x * x; }
11 inline int cu(const int x) { return x * x * x; }
12
13 int main()
14 {
15 cout.flags(ios::fixed);
16 cout.precision(4);
17
18 cin >> a1 >> b1 >> c1 >> d1;
19 cin >> a2 >> b2 >> c2 >> d2;
20
21 int t = sq(a1 - a2) + sq(b1 - b2) + sq(c1 - c2);
22
23 if (t <= sq(d2 - d1)) cout << cu(min(d1, d2)) * r * 4;
24 else if (t >= sq(d2 + d1)) cout << 0;
25 else {
26 double x = d1 - (sq(d1) - sq(d2) + t) / sqrt(t) / 2;
27 double y = d2 - (sq(d2) - sq(d1) + t) / sqrt(t) / 2;
28 cout << (x * x * (3 * d1 - x) + y * y * (3 * d2 - y)) * r;
29 }
30 cout << endl;
31 return 0;
32 }
假设输入的所有数的绝对值都不超过 1000,完成下面的判断题和单选题:
判断题
- 将第 21 行中 t 的类型声明从 int 改为 double,不会影响程序运行的结果。( )
- 将第 26、27 行中的“/ sqrt(t) / 2”替换为“/ 2 / sqrt(t)”,不会影响程序运行的结果。( )
- 将第 28 行中的“x * x”改成“sq(x)”、“y * y”改成“sq(y)” ,不会影响程序运行的结果。( )
- 当输入为“0 0 0 1 1 0 0 1”时,输出为“1.3090”。( )
单选题
-
当输入为“1 1 1 1 1 1 1 2”时,输出为( )。
A. “3.1416”
B. “6.2832”
C. “4.7124”
D. “4.1888” -
这段代码的含义为( )。
A. 求圆的面积并
B. 求球的体积并
C. 求球的体积交
D. 求椭球的体积并
【题目考点】
1. 数学:求球的体积交
球的体积公式V=43πr3V=\frac{4}{3}\pi r^3V=34πr3,rrr是球的半径。
求两球相交的体积
现有两球,第一个求半径为r1r_1r1,球心为C1C_1C1。第二个球半径为r2r_2r2,球心为C2C_2C2,两球球心之间的距离为ddd。
- 如果d≥r1+r2d\ge r_1+r_2d≥r1+r2,两球不相交,相交体积为0。
- 如果d≤∣r2−r1∣d\le|r_2-r_1|d≤∣r2−r1∣
不失一般性,假设r1<r2r_1<r_2r1<r2,那么d≤r2−r1d\le r_2-r_1d≤r2−r1,即r1+d≤r2r_1+d\le r_2r1+d≤r2,第一个球中距离第二个球球心C2C_2C2最远的点,到C2C_2C2的距离为r1+dr_1+dr1+d,由于r1+d≤r2r_1+d\le r_2r1+d≤r2,所以第一个球的所有点都在第二个球之中,即第一个球被第二个球包含,因此两球相交体积为第一个球的体积,即半径较小的球的体积。
因此两球相交的体积为43πmin{r1,r2}3\frac{4}{3}\pi \min\{r_1,r_2\}^334πmin{r1,r2}3 - 如果∣r2−r1∣<d<r1+r2|r_2-r_1|<d<r_1+r_2∣r2−r1∣<d<r1+r2,那么两球相交的部分为两个球缺。
球缺是指球体被平面截去一部分后剩余的部分。上图小圆面上方部分即为球缺。
垂直于截面的直径被此截面截得的线段长称为球缺的高,图中球缺的高为h。已知球半径r,以及球缺的高h,求球缺的体积。
可以将球缺横向切成很多个近似的小圆柱,每个圆柱的底面积是一个球的截面圆的面积,高为微分dxdxdx,进行积分。
设截面圆圆心B到球缺高与球面交点A的长度AB=xAB=xAB=x,那么BO=r−xBO=r-xBO=r−x,截面圆半径BCBCBC的平方为r2−(r−x)2r^2-(r-x)^2r2−(r−x)2,截面圆面积为π(r2−(r−x)2)\pi(r^2-(r-x)^2)π(r2−(r−x)2),一个小圆柱的体积为π(r2−(r−x)2) dx\pi(r^2-(r-x)^2)\,dxπ(r2−(r−x)2)dx,xxx最小为0,最大为球缺的高hhh,因此球缺的体积为:
∫0hπ(r2−(r−x)2) dx=∫0hπ(r2−r2−x2+2rx) dx=π∫0h(2rx−x2) dx=π(rx2∣0h−x33∣0h)=π(rh2−h33)=π3(3r−h)h2\int_0^h\pi(r^2-(r-x)^2)\,dx\\
=\int_0^h\pi(r^2-r^2-x^2+2rx)\,dx\\
=\pi \int_0^h(2rx-x^2)\,dx\\
=\pi(rx^2|_0^h-\frac{x^3}{3}|_0^h)\\
=\pi(rh^2-\frac{h^3}{3})\\
=\frac{\pi}{3}(3r-h)h^2∫0hπ(r2−(r−x)2)dx=∫0hπ(r2−r2−x2+2rx)dx=π∫0h(2rx−x2)dx=π(rx2∣0h−3x3∣0h)=π(rh2−3h3)=3π(3r−h)h2
因此半径为r,球缺高为h的球缺体积V′=π3(3r−h)h2V'=\dfrac{\pi}{3}(3r-h)h^2V′=3π(3r−h)h2
两球相交如图所示:
球心为C1C_1C1的球半径为r1r_1r1,球心为C2C_2C2的求半径为r2r_2r2
两球心之间的距离C1C2=dC_1C_2=dC1C2=d,红色线表示两球相交的截面,截面与球心连线垂直,ABABAB是截面中的一条线,因此有AB⊥C1C2AB\perp C_1C_2AB⊥C1C2
设BC2=xBC_2=xBC2=x,则BC1=d−xBC_1=d-xBC1=d−x
根据勾股定理AC12−BC12=AB2=AC22−BC22AC_1^2-BC_1^2=AB^2=AC_2^2-BC_2^2AC12−BC12=AB2=AC22−BC22
所以r12−(d−x)2=r22−x2r_1^2-(d-x)^2=r_2^2-x^2r12−(d−x)2=r22−x2
r12−d2−x2+2dx=r22−x2r_1^2-d^2-x^2+2dx=r_2^2-x^2r12−d2−x2+2dx=r22−x2
2dx=r22−r12+d22dx=r_2^2-r_1^2+d^22dx=r22−r12+d2
x=r22−r12+d22dx=\dfrac{r_2^2-r_1^2+d^2}{2d}x=2dr22−r12+d2
两球相交部分中,以C2C_2C2为球心的球的球缺的高为:
h2=BP2=C2P2−C2B=r2−x=r2−r22−r12+d22dh_2=BP_2=C_2P_2-C_2B=r_2-x=r_2-\dfrac{r_2^2-r_1^2+d^2}{2d}h2=BP2=C2P2−C2B=r2−x=r2−2dr22−r12+d2
以C1C_1C1为球心的球的球缺的高为:
h1=BP1=C1P1−C1B=r1−(d−x)=r1−(d−r22−r12+d22d)=r1−2d2−r22+r12−d22d=r1−r12−r22+d22dh_1=BP_1=C_1P_1-C_1B=r_1-(d-x)\\
=r_1-(d-\dfrac{r_2^2-r_1^2+d^2}{2d})\\
=r_1-\dfrac{2d^2-r_2^2+r_1^2-d^2}{2d}\\
=r_1-\dfrac{r_1^2-r_2^2+d^2}{2d}h1=BP1=C1P1−C1B=r1−(d−x)=r1−(d−2dr22−r12+d2)=r1−2d2d2−r22+r12−d2=r1−2dr12−r22+d2
总结:两球相交部分为两个球缺
第一个球的球缺半径为r1r_1r1,高为h1=r1−r12−r22+d22dh_1=r_1-\dfrac{r_1^2-r_2^2+d^2}{2d}h1=r1−2dr12−r22+d2,体积为π3(3r1−h1)h12\dfrac{\pi}{3}(3r_1-h_1)h_1^23π(3r1−h1)h12
第二个球的球缺半径为r2r_2r2,高为h2=r2−r22−r12+d22dh_2=r_2-\dfrac{r_2^2-r_1^2+d^2}{2d}h2=r2−2dr22−r12+d2,体积为π3(3r2−h2)h22\dfrac{\pi}{3}(3r_2-h_2)h_2^23π(3r2−h2)h22
球相交部分体积为:π3((3r1−h1)h12+(3r2−h2)h22)\dfrac{\pi}{3}((3r_1-h_1)h_1^2+(3r_2-h_2)h_2^2)3π((3r1−h1)h12+(3r2−h2)h22)
2. 数学:反三角函数
【解题思路】
10 inline int sq(const int x) { return x * x; }
11 inline int cu(const int x) { return x * x * x; }
函数sq(x)
求x的平方,cu(x)
求x的立方。inline表示该函数是内联函数,在编译后不进行真正的函数调用,可以加快运行速度。
15 cout.flags(ios::fixed);
16 cout.precision(4);
这两句是作用是以下进行输出浮点型量时,会保留四位小数输出。
18 cin >> a1 >> b1 >> c1 >> d1;
19 cin >> a2 >> b2 >> c2 >> d2;
20
21 int t = sq(a1 - a2) + sq(b1 - b2) + sq(c1 - c2);
输入a1,b1,c1,d1,a2,b2,c2,d2a_1,b_1,c_1,d_1,a_2,b_2,c_2,d_2a1,b1,c1,d1,a2,b2,c2,d2 8个变量,看变量名大概可以推测:a1,b1,c1,d1a_1,b_1,c_1,d_1a1,b1,c1,d1是相关的四个量,a2,b2,c2,d2a_2,b_2,c_2,d_2a2,b2,c2,d2是相关的四个量。
t的值为t=(a1−a2)2+(b1−b2)2+(c1−c2)2t=(a_1-a_2)^2+(b_1-b_2)^2+(c_1-c_2)^2t=(a1−a2)2+(b1−b2)2+(c1−c2)2
05 const double r = acos(0.5);
已知弧度与角度的转化关系:π 弧度=180角度\pi\ 弧度 = 180角度π 弧度=180角度
设有直角三角形,∠A=60°=π3\angle A=60\degree= \frac{\pi}{3}∠A=60°=3π,∠B=30°=π6\angle B=30\degree=\frac{\pi}{6}∠B=30°=6π,∠C=90°=π2\angle C=90\degree=\frac{\pi}{2}∠C=90°=2π,那么∠A\angle A∠A的余弦值,即∠A\angle A∠A邻边比斜边的比值为cosπ3=12cos\frac{\pi}{3}=\frac{1}{2}cos3π=21,arccos\arccosarccos是coscoscos的反三角函数,所以arccos12=π3arccos \frac{1}{2} = \frac{\pi}{3}arccos21=3π
代码中r的值为r=arccos12=π3r=arccos \frac{1}{2} = \dfrac{\pi}{3}r=arccos21=3π
23 if (t <= sq(d2 - d1)) cout << cu(min(d1, d2)) * r * 4;
24 else if (t >= sq(d2 + d1)) cout << 0;
当t≤(d2−d1)2t\le (d_2-d_1)^2t≤(d2−d1)2时,输出4r(min{d1,d2})3=43π(min{d1,d2})34r(\min\{d_1,d_2\})^3=\frac{4}{3}\pi(\min\{d_1,d_2\})^34r(min{d1,d2})3=34π(min{d1,d2})3
看这个公式的形式,符合球的体积公式,因此min{d1,d2}\min\{d_1,d_2\}min{d1,d2}应该是球的半径,这是输出了半径为min{d1,d2}\min\{d_1,d_2\}min{d1,d2}的球的体积。
当t≥(d2+d1)2t\ge (d_2+d_1)^2t≥(d2+d1)2时,输出0。
结合ttt的定义,看到这里时,基本可以确定(a1,b1,c1)(a_1,b_1,c_1)(a1,b1,c1)是第1个球的球心,半径为d1d_1d1。(a2,b2,c2)(a_2,b_2,c_2)(a2,b2,c2)为第2个球的球心,半径为d2d_2d2。
两个球心的距离为(a1−a2)2+(b1−b2)2+(c1−c2)2=t\sqrt{(a_1-a_2)^2+(b_1-b_2)^2+(c_1-c_2)^2} = \sqrt{t}(a1−a2)2+(b1−b2)2+(c1−c2)2=t,因此ttt是两球心距离的平方。
- 当球心距离t≤∣d2−d1∣\sqrt{t}\le |d_2-d_1|t≤∣d2−d1∣时,半径为max{d1,d2}\max\{d_1,d_2\}max{d1,d2}的球包含半径为min{d1,d2}\min\{d_1,d_2\}min{d1,d2}的球,两球交(重合)的部分的体积为较小球的体积43π(min{d1,d2})3\frac{4}{3}\pi(\min\{d_1,d_2\})^334π(min{d1,d2})3。
- 当球心距离t≥∣d2+d1∣\sqrt{t}\ge |d_2+d_1|t≥∣d2+d1∣时,两球不相交,相交体积为0。
- 当球心距离∣d2−d1∣<t<∣d2+d1∣|d_2-d_1|<\sqrt{t}<|d_2+d_1|∣d2−d1∣<t<∣d2+d1∣时,就要球两球相交的体积。
26 double x = d1 - (sq(d1) - sq(d2) + t) / sqrt(t) / 2;
27 double y = d2 - (sq(d2) - sq(d1) + t) / sqrt(t) / 2;
28 cout << (x * x * (3 * d1 - x) + y * y * (3 * d2 - y)) * r;
相信高中不会教这个知识点,我们做这个题也不需要真的了解求两球相交体积的方法,只要看出该题求的是球相交的体积,就可以把下面的题做对。
具体的求球相交体积的原理见上文【题目考点】。
h1=r1−r12−r22+d22dh_1=r_1-\dfrac{r_1^2-r_2^2+d^2}{2d}h1=r1−2dr12−r22+d2,h2=r2−r22−r12+d22dh_2=r_2-\dfrac{r_2^2-r_1^2+d^2}{2d}h2=r2−2dr22−r12+d2,
球相交的体积为π3((3r1−h1)h12+(3r2−h2)h22)\dfrac{\pi}{3}((3r_1-h_1)h_1^2+(3r_2-h_2)h_2^2)3π((3r1−h1)h12+(3r2−h2)h22)
本题d1d_1d1为公式中的r1r_1r1,本题d2d_2d2为公式中的r2r_2r2,本题t\sqrt{t}t为公式中的ddd。本题xxx为公式中的h1h_1h1,本题yyy为公式中的h2h_2h2。本题rrr为π3\dfrac{\pi}{3}3π。
题目中的代码就是在实现上述公式,可以求出两球相交的体积。
判断题
1. 将第 21 行中 t 的类型声明从 int 改为 double,不会影响程序运行的结果。( )
答:T
将t设为double类型后,下面代码中t参与的表达式的计算过程从整数计算变为了实数计算,虽说进行实数计算有可能产生偏差,不过绝大部分情况下不会出现精度问题,可以认为不会影响程序结果。
2. 将第 26、27 行中的“/ sqrt(t) / 2”替换为“/ 2 / sqrt(t)”,不会影响程序运行的结果。( )
答:F
26 double x = d1 - (sq(d1) - sq(d2) + t) / sqrt(t) / 2;
27 double y = d2 - (sq(d2) - sq(d1) + t) / sqrt(t) / 2;
表达式(sq(d1) - sq(d2) + t)
的值是int类型的,sqrt(t)
的值是double类型的,二者相除会进行实数除法,再除以2也是进行实数除法,会得到小数结果。
如果改为
26 double x = d1 - (sq(d1) - sq(d2) + t) / 2 / sqrt(t);
27 double y = d2 - (sq(d2) - sq(d1) + t) / 2 / sqrt(t);
表达式(sq(d1) - sq(d2) + t)
的值是int类型的,2
也是int类型的,二者相除会进行整数除法运算,正整数进行整数除法,商为实数除法的商向下取整(如5/2
表达式的值为2
)。因此这一步进行实数除法可能会产生精度丢失,表达式的值与预期进行实数除法的结果不同。再进行后续计算,结果也是错误的。
因此修改后会影响程序运行的结果。
3. 将第 28 行中的“x * x”改成“sq(x)”、“y * y”改成“sq(y)” ,不会影响程序运行的结果。( )
答:F
由于sq函数的定义为
10 inline int sq(const int x) { return x * x; }
参数类型为int,而第28行使用的x、y为double类型的变量,将double类型量传给int类型的参数,会发生double到int的类型转化,可能会丢失精度。而第28行求的是实数x或y的平方,不能使用求整数平方的sq函数。
例:x的值为1.5,传入sq函数后,sq函数内参数x的值为1,
sq(x)
返回1。而x*x
表达式的值为2.25。
4. 当输入为“0 0 0 1 1 0 0 1”时,输出为“1.3090”。( )
答:T
第一个球的球心为(0,0,0)(0,0,0)(0,0,0),半径为1。第二个球的球心为(1,0,0)(1, 0, 0)(1,0,0),半径为1。两求的交
求出t=(a1−a2)2+(b1−b2)2+(c1−c2)2=1t=(a_1-a_2)^2+(b_1-b_2)^2+(c_1-c_2)^2=1t=(a1−a2)2+(b1−b2)2+(c1−c2)2=1
根据这段代码的逻辑进行手算:
26 double x = d1 - (sq(d1) - sq(d2) + t) / sqrt(t) / 2;
27 double y = d2 - (sq(d2) - sq(d1) + t) / sqrt(t) / 2;
28 cout << (x * x * (3 * d1 - x) + y * y * (3 * d2 - y)) * r;
x=d1−(d12−d22+t)/t/2=1−(1−1+1)/1/2=0.5x=d_1-(d_1^2-d_2^2+t)/\sqrt{t}/2=1-(1-1+1)/1/2=0.5x=d1−(d12−d22+t)/t/2=1−(1−1+1)/1/2=0.5
y=d2−(d22−d12+t)/t/2=1−(1−1+1)/1/2=0.5y=d_2-(d_2^2-d_1^2+t)/\sqrt{t}/2=1-(1-1+1)/1/2=0.5y=d2−(d22−d12+t)/t/2=1−(1−1+1)/1/2=0.5
输出值(x2(3d1−x)+y2(3d2−y))r=14(3∗1−0.5+3∗1−0.5)∗π3=5π12(x^2(3d_1-x)+y^2(3d_2-y))r\\=\frac{1}{4}(3*1-0.5+3*1-0.5)*\frac{\pi}{3}\\
=\frac{5\pi}{12}(x2(3d1−x)+y2(3d2−y))r=41(3∗1−0.5+3∗1−0.5)∗3π=125π
由于最终结果要求保留到小数点后4位,因此π\piπ取到小数点后5位进行计算。
5π12≈5∗3.1415912=1.308995≈1.3090\frac{5\pi}{12}\approx\frac{5*3.14159}{12}=1.308995\approx 1.3090125π≈125∗3.14159=1.308995≈1.3090。
该叙述正确。
单选题
5. 当输入为“1 1 1 1 1 1 1 2”时,输出为( )。
A. “3.1416”
B. “6.2832”
C. “4.7124”
D. “4.1888”
答:D
第一个球的球心为(1,1,1)(1,1,1)(1,1,1),半径为1。第二个球的球心为(1,1,1)(1,1,1)(1,1,1),半径为2。显然第二个球包含第一个球,两个求的相交部分为第一个球的体积,为
V=43πr3=43πV=\frac{4}{3}\pi r^3=\frac{4}{3}\piV=34πr3=34π
由于最终结果要求保留到小数点后4位,因此π\piπ取到小数点后5位进行计算。
43π≈4∗3.141593=4.18878≈4.1888\frac{4}{3}\pi\approx\frac{4*3.14159}{3}=4.18878\approx 4.188834π≈34∗3.14159=4.18878≈4.1888,因此选D。
6. 这段代码的含义为( )。
A. 求圆的面积并
B. 求球的体积并
C. 求球的体积交
D. 求椭球的体积并
答:C
本题求的是两球相交部分的体积,选C。
【答案】
- T
- F
- F
- T
- D
- C