天天看點

空間中兩球的體積并(積分)

連結:​​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塊構成的,分别屬于兩個球體。其中一塊的體積公式為(以大球為例):

空間中兩球的體積并(積分)
空間中兩球的體積并(積分)
空間中兩球的體積并(積分)
空間中兩球的體積并(積分)
空間中兩球的體積并(積分)
空間中兩球的體積并(積分)
空間中兩球的體積并(積分)
空間中兩球的體積并(積分)