什麼是球冠和球缺
如上圖,是一個以 點爲球心, 爲半徑,截去下半部分的球冠,它的表面積和體積公式如下:
如果我們可以得到 和 的值,那麼我們就可以知道這個球缺的表面積和體積,所以對於球相交的表面積和體積這類問題,只要求出 ,基本上就做完啦。
我們已知兩個球的球心和半徑,需要求兩個球的表面積並/體積。
顯然兩個球相交的相交部分是兩個球缺,所以我們只需要求出這兩個球的球缺的表面積/體積,就可以算出答案,要求出球缺的表面積/體積,並且已知球的半徑 ,顯然只需要求出球缺的高 就可以了。
下面我以求 球 的高 爲例,先求出圓心之間的距離 ,已知 ,由 和餘弦定理,可以求出 的值,然後由直角三角形 可以求出線段 的長度 ,最後 。
然後用兩個球的總表面積/體積 減去 兩個球缺的總表面積/體積 就可以得到答案了。
注意,一般這樣的題目要先判斷兩個球的關係是 內含、相交,還是外離。若內含或外離,直接輸出答案即可。
牛客小白月賽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 (o.r < 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 <= o.r - 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 = o.r - 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 * o.r - H)*H*H;
}
else if (dis < o.r + 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 * o.r * dis));
double H = o.r - o.r * cos(angleR);
double h = t.r - t.r * cos(angler);
return PI / 3 * (3 * t.r - h)*h*h + PI / 3 * (3 * o.r - 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);
}
}