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)); } } }