链接: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块构成的,分别属于两个球体。其中一块的体积公式为(以大球为例):