牛客小白月赛20 C 关于球相交的表面积和体积并
什么是球冠和球缺
如上图,是一个以 点为球心, 为半径,截去下半部分的球冠,它的表面积和体积公式如下:
如果我们可以得到 和 的值,那么我们就可以知道这个球缺的表面积和体积,所以对于球相交的表面积和体积这类问题,只要求出 ,基本上就做完啦。
我们已知两个球的球心和半径,需要求两个球的表面积并/体积。
显然两个球相交的相交部分是两个球缺,所以我们只需要求出这两个球的球缺的表面积/体积,就可以算出答案,要求出球缺的表面积/体积,并且已知球的半径 ,显然只需要求出球缺的高 就可以了。
下面我以求 球 的高 为例,先求出圆心之间的距离 ,已知 ,由 和余弦定理,可以求出 的值,然后由直角三角形 可以求出线段 的长度 ,最后 。
然后用两个球的总表面积/体积 减去 两个球缺的总表面积/体积 就可以得到答案了。
注意,一般这样的题目要先判断两个球的关系是 内含、相交,还是外离。若内含或外离,直接输出答案即可。
牛客小白月赛20 C
球的表面积并
Code:
#include <bits/stdc++.h> #define ll long long using namespace std; const double PI = acos(-1.0); struct point { double x; double y; double z; }; struct circle { point o; double r; } a, b; double getlen(point a, point b) { double ans = sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y) + (a.z - b.z) * (a.z - b.z)); return ans; } int main() { scanf("%lf%lf%lf%lf", &a.o.x, &a.o.y, &a.o.z, &a.r); scanf("%lf%lf%lf%lf", &b.o.x, &b.o.y, &b.o.z, &b.r); assert(-100000 <= a.o.x && a.o.x <= 100000); assert(-100000 <= a.o.y && a.o.y <= 100000); assert(-100000 <= a.o.z && a.o.z <= 100000); assert(0 < a.r && a.r <= 100000); assert(-100000 <= b.o.x && b.o.x <= 100000); assert(-100000 <= b.o.y && b.o.y <= 100000); assert(-100000 <= b.o.z && b.o.z <= 100000); assert(0 < b.r && b.r <= 100000); if (a.r > b.r) swap(a, b); double dis = getlen(a.o, b.o); if (dis + a.r <= b.r) { double r = max(a.r, b.r); double ans = 4 * PI * r * r; printf("%.6lf", ans); } else if (dis < a.r + b.r && dis + a.r > b.r) { double angle_cosa = (a.r * a.r + dis * dis - b.r * b.r) / (2 * a.r * dis); double angle_cosb = (b.r * b.r + dis * dis - a.r * a.r) / (2 * b.r * dis); double len_a = a.r - a.r * angle_cosa; double len_b = b.r - b.r * angle_cosb; double ans = 4 * PI * (a.r * a.r + b.r * b.r); ans -= 2 * PI * (a.r * len_a + b.r * len_b); printf("%.6lf", ans); } else { double ans = 4 * PI * (a.r * a.r + b.r * b.r); printf("%.6lf", ans); } }
Wannafly winter camp 2019 day2 H
球的体积并
code:
#include <bits/stdc++.h> const double PI = acos(-1.0); using namespace std; struct node { double x; double y; double z; double r; }que[105], o; double calc(node o, node t) { if&nbs***bsp;< t.r) swap(o, t); double dis = sqrt((o.x - t.x)*(o.x - t.x) + (o.y - t.y)*(o.y - t.y) + (o.z - t.z)*(o.z - t.z)); if (dis <=&nbs***bsp;- t.r) { return 4.0 / 3 * PI * t.r * t.r * t.r; } else if (dis <= o.r) { double angleb = acos((t.r*t.r + dis * dis - o.r*o.r) / (2 * t.r * dis)); double anglea = PI - angleb; double l = t.r*cos(anglea); double H =&nbs***bsp;- l - dis; double h = t.r - l; return 4.0 / 3 * PI * t.r * t.r * t.r - PI / 3 * (3 * t.r - h)*h*h + PI / 3 * (3 *&nbs***bsp;- H)*H*H; } else if (dis <&nbs***bsp;+ t.r) { double angler = acos((t.r*t.r + dis * dis - o.r*o.r) / (2 * t.r * dis)); double angleR = acos((o.r*o.r + dis * dis - t.r*t.r) / (2 *&nbs***bsp;* dis)); double H =&nbs***bsp;-&nbs***bsp;* cos(angleR); double h = t.r - t.r * cos(angler); return PI / 3 * (3 * t.r - h)*h*h + PI / 3 * (3 *&nbs***bsp;- H)*H*H; } return 0; } int main() { int t, n, cas = 1; scanf("%d", &t); while (t--) { scanf("%d", &n); for (int i = 0; i < n; i++) scanf("%lf%lf%lf%lf", &que[i].x, &que[i].y, &que[i].z, &que[i].r); scanf("%lf%lf%lf%lf", &o.x, &o.y, &o.z, &o.r); double ans = 0; for (int i = 0; i < n; i++) ans += calc(o, que[i]); printf("Case #%d: %.6lf\n", cas++, ans); } }