题意
给我们两个大小不同的圆的半径小圆是实心的 大圆是空心的 然后给我们一个小球的半径 小球的初始位置 还有飞碟在x方向和y方向上的速度 小球撞到内实心圆会能量不损失的反弹 问小球任何位置与大圆相交到完全出去的时间是多少
分析
几何题 如何知道时间呢
如果小球与大圆相切或是无交点 那么小球所求的时间是0
如果小球与内圆相切或是无交点 那么小球所求的时间就是在内圆的交点处的两个时间相减
如果小球与内院发生撞击 那么小球回反射 由于能量不递减 并且反射面是个球面 计算时间的范围也是个球面那么也就相当于求怎么进来的大圆 就会反射出一个不同向的相同时间的轨迹 那么我们求出求进来大圆的时间 和小球撞击内圆的时间 两个作差乘2就能得到解
那么问题其实就相当于如何求出交点处的时间点是多少
我们知道小球的运动轨迹以及方程
x′=x0+vx∗t
y′=y0+vy∗t
还知道两个圆的方程
x2+y2 = Rm2
x2+y2 = R2
由于初始位置,半径已知所以其中唯一的变量就是t
那么我们把运动轨迹方程带入到第一个圆的等式中 求得t 也就是小球经过第一个圆的交点处的t
(x0+vx∗t)2+(y+vy∗t)2 = (R+r)2
我们把运动轨迹方程代入到第二个圆的等式中 求得t也就是小球经过的第二个圆的交点处的t
(x0+vx∗t)2+(y+vy∗t)2 = (Rm+r)2
注意不同情况 我们需要不同的t去求结果
化简可得
(vx2+vy2)∗t2 +(2y∗vy+2x∗vx)∗t - (R+r)2 =0
那么这里就会产生一个问题 如果球轨迹所在直线和内圆相交 但是方向相反 由于代入等式是个二次方的
会无视方向 这里就需要判断下
如果让球动一点 球与内圆圆心的距离边长了 那么就说明永不会相交 直接输出0.000
所以 根据不同情况 解方程即可
CODE
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const double eps = 1e-8;
double dis(double x1,double y1,double x2,double y2){return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}
int main()
{double Rm,R,r,x,y,vx,vy;while(~scanf("%lf%lf%lf%lf%lf%lf%lf",&Rm,&R,&r,&x,&y,&vx,&vy)){double ans,C = x*x+y*y-(R+r)*(R+r);double B = 2*y*vy+2*x*vx;double A = vy*vy+vx*vx;double jud = B*B-4*A*C;double x2 = x+vx,y2 = y+vy;if(dis(x2,y2,0,0)-dis(x,y,0,0)>eps){//判断是否反向puts("0.000");continue;}if(jud-0<=eps){puts("0.000");continue;}double t1 = (-B-sqrt(jud))/(2*A);double t2 = (-B+sqrt(jud))/(2*A);double C2 = x*x+y*y-(Rm+r)*(Rm+r);double jud2 = B*B-4*A*C2;if(jud2-0<=eps){printf("%.3lf\n",t2-t1);continue;}double t3 = (-B-sqrt(jud2))/(2*A);printf("%.3lf\n",fabs((t1-t3)*2));}return 0 ;
}