链接:https://ac.nowcoder.com/acm/contest/373/E
来源:牛客网
题目描述
某天lililalala正在玩一种奇妙的吃鸡游戏--因为在这个游戏里会同时有两个圆形安全区(他们可能相交)。
lililalala觉得求圆的面积并太简单了,所以想把这个问题升级一下。
现在在三维空间里有 2 个球形安全区,分别用四元组 <x1,y1,z1,r1> <x1,y1,z1,r1> 和 <x2,y2,z2,r2> <x2,y2,z2,r2>表示,其中 r1、r2 r1、r2表示球半径, (x1,y1,z1) (x1,y1,z1)和 (x2,y2,z2) (x2,y2,z2)表示球心
lililalala想知道安全区的总体积是多少?即求这两个球的体积并。
输入描述:
输入有两行。
第一行四个实数 x1,y1,z1,r1 x1,y1,z1,r1--第一个球的球心坐标和半径。
第二行四个实数 x2,y2,z2,r2 x2,y2,z2,r2--第二个球的球心坐标和半径。
保证所有输入的坐标和半径的范围都在 [−100,100] [−100,100] 内。
输出描述:
输出一行一个实数--表示两个球的体积并,你的答案被认为正确,当且仅当绝对误差不超过 10−6 10−6。
示例1
输入
0 0 0 1 2 0 0 1
输出
8.3775804
示例2
输入
0 0 0 1 0 0 0 0.5
输出
4.1887902
牛客网参考代码:
#include <bits/stdc++.h>
using namespace std;
const double pi = acos(-1);
struct ball{
double x,y,z,r;
ball(double x=0,double y=0,double z=0,double r=0):x(x),y(y),z(z),r(r){}
double dist(ball a){
return sqrt((x-a.x)*(x-a.x)+(y-a.y)*(y-a.y)+(z-a.z)*(z-a.z));
}
double v(){
return pi*r*r*r*4/3;
}
}a,b;
double solve(){
double d = a.dist(b);
if(d-a.r-b.r>0)return a.v()+b.v();
double r1=a.r,r2=b.r;
if(d+r1<r2||d+r2<r1)return max(a.v(),b.v());
double v1=pi/3*(r1-(r1*r1-r2*r2+d*d)/(2*d))*(r1-(r1*r1-r2*r2+d*d)/(2*d));
v1 *= 3*r1- (r1-(r1*r1-r2*r2+d*d)/(2*d));
double v2=pi/3*(r2-(r2*r2-r1*r1+d*d)/(2*d))*(r2-(r2*r2-r1*r1+d*d)/(2*d));
v2 *= 3*r2- (r2-(r2*r2-r1*r1+d*d)/(2*d));
return a.v()+b.v()-(v1+v2);
}
int main(){
scanf("%lf%lf%lf%lf",&a.x,&a.y,&a.z,&a.r);
scanf("%lf%lf%lf%lf",&b.x,&b.y,&b.z,&b.r);
printf("%.7f\n",solve());
return 0;
}
笔者代码:
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
const double pi=acos(-1.0);
double x[2],y[2],z[2];
double R,r;
double d;
int main()
{
scanf("%lf%lf%lf%lf%lf%lf%lf%lf",&x[0],&y[0],&z[0],&R,&x[1],&y[1],&z[1],&r);
double d=sqrt((x[0]-x[1])*(x[0]-x[1])+(y[0]-y[1])*(y[0]-y[1])+(z[0]-z[1])*(z[0]-z[1]));
double v1=4*pi*R*R*R/3,v2=4*pi*r*r*r/3;
if(d>=R+r)
printf("%.7lf\n",v1+v2);
else if(fabs(R-r)>=d)
printf("%.7lf\n",max(v1,v2));
else
{
if(R<r) swap(R,r);
double insrt=(pi*(R+r-d)*(R+r-d)*(d*d+2*d*r-3*r*r+2*d*R+6*r*R-3*R*R))/(12*d);
printf("%.7lf\n",v1+v2-insrt);
}
return 0;
}
另外附证明公式:
证明:
相交部分体积是由2块构成的,分别属于两个球体。其中一块的体积公式为(以大球为例):