题意
给我们两个大小不同的圆的半径小圆是实心的 大圆是空心的 然后给我们一个小球的半径 小球的初始位置 还有飞碟在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 ;
}