F. Girlfriend


题面:多组输入,已知四个点,和动点到两点距离的比值范围,求轨迹交出来的体积。(计算几何)
解析:先把它看作二维,方便理解。
一个点到两定点的距离成比例,初中老师告诉过我们叫 阿波罗尼斯圆
如果不记得也没有关系,用样例推一下,两个动点的轨迹都是圆,自然而然地向外推广。
而圆最重要的是圆心和半径,根据轨迹可知在在过两定点的直线上必定是圆的直径,通过坐标关系得到圆上两点的坐标,即可得到圆的圆心坐标和半径。
此时重新看作三维,以上过程不变。问题就转化成求两球相交的体积。
分类讨论,不相交,包含关系,相交无包含关系。
相交时公式推导链接说明
上代码

#include<bits/stdc++.h>
using namespace std;
typedef double dd;
#define pi 3.1415926
int t;
struct {
    dd x,y,z;
}s[1005];
dd k1,k2;
dd di(dd x1,dd y1,dd z1,dd x2,dd y2,dd z2){
    return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)+(z1-z2)*(z1-z2));
}
dd zuo1(dd x1,dd x2,dd k) {
    return (k*x2+x1)/(k+1);
}
dd zuo2(dd x1,dd x2,dd k) {
    return (k*x2-x1)/(k-1);
}
dd p(dd r1,dd r2,dd d) {
    return (r1*r1+d*d-r2*r2)/2.0/r1/d;
}


int main()
{
    cin>>t;
    while(t--){
        for(int i=1;i<=4;i++)
        cin>>s[i].x>>s[i].y>>s[i].z;
        cin>>k1>>k2;
        dd t1=zuo1(s[1].x,s[2].x,k1);
        dd t2=zuo1(s[1].y,s[2].y,k1);
        dd t3=zuo1(s[1].z,s[2].z,k1);
        dd t4=zuo2(s[1].x,s[2].x,k1);
        dd t5=zuo2(s[1].y,s[2].y,k1);
        dd t6=zuo2(s[1].z,s[2].z,k1);
        dd r1=(zuo1(s[1].x,s[2].x,k1)+zuo2(s[1].x,s[2].x,k1))/2.0;
        dd r2=(zuo1(s[1].y,s[2].y,k1)+zuo2(s[1].y,s[2].y,k1))/2.0;
        dd r3=(zuo1(s[1].z,s[2].z,k1)+zuo2(s[1].z,s[2].z,k1))/2.0;
        dd r0=di(t1,t2,t3,t4,t5,t6)/2.0;

        dd t11=zuo1(s[3].x,s[4].x,k2);
        dd t21=zuo1(s[3].y,s[4].y,k2);
        dd t31=zuo1(s[3].z,s[4].z,k2);
        dd t41=zuo2(s[3].x,s[4].x,k2);
        dd t51=zuo2(s[3].y,s[4].y,k2);
        dd t61=zuo2(s[3].z,s[4].z,k2);
        dd r11=(zuo1(s[3].x,s[4].x,k2)+zuo2(s[3].x,s[4].x,k2))/2.0;
        dd r21=(zuo1(s[3].y,s[4].y,k2)+zuo2(s[3].y,s[4].y,k2))/2.0;
        dd r31=(zuo1(s[3].z,s[4].z,k2)+zuo2(s[3].z,s[4].z,k2))/2.0;
        dd r01=di(t11,t21,t31,t41,t51,t61)/2.0;

        dd d=di(r1,r2,r3,r11,r21,r31);
        //printf("%.6lf\n%.6lf\n",t11,t41);        
        if(r01+r0<=d) cout<<"0.000"<<endl;
        else if(r01-r0>=d) printf("%.6lf\n",4.0*pi*r0*r0*r0/3.0);
        else if(r0-r01>=d) printf("%.6lf\n",4.0*pi*r01*r01*r01/3.0);
        else {

            dd h1=r0*(1-p(r0,r01,d));
            dd h2=r01*(1-p(r01,r0,d));
            printf("%.6lf\n",pi*(r0*h1*h1+r01*h2*h2-h1*h1*h1/3.0-h2*h2*h2/3.0));
        }

    }
}