题目大意 :有一个圆硬币半径为r,初始位置为x,y,速度矢量为vx,vy,有一个圆形区域(圆心在原点)半径为R,还有一个圆盘(圆心在原点)半径为Rm (Rm < R),圆盘固定不动,硬币撞到圆盘上会被反弹,不考虑能量损失,求硬币在圆形区域内运动的时间。
运动方程:
x'=x+t*vx;
y'=y+t*vy;
r'=r1+r2;
x'^2+y'^2=r'^2;
难点在于如何构造出两个运动轨迹方程,为什么这么构造。
一共四种情况:
第一种:与外圆相离相切,输出0。
第二种:与外圆相交,与内圆相离相切,输出外圆两个解的差的绝对值。
第三种:与外圆相交,与内圆相交,输出外圆两个解的差的绝对值减去内圆两个解的差的绝对值。
第四种:与外圆相交即有两个解,但是两个解都是负的(要么都是负数要么都是正数),也就是说反向运动才能进入大圆,输出0。
#include <bits/stdc++.h> const double eps=0.00000001; using namespace std; int main() { double Rm,R,r,x,y,vx,vy,k,b,flag; while(scanf("%lf%lf%lf%lf%lf%lf%lf",&Rm,&R,&r,&x,&y,&vx,&vy)!=EOF) { double a1=vx*vx+vy*vy; double b1=2*x*vx+2*y*vy; double c1=x*x+y*y-(R+r)*(R+r); double a2=vx*vx+vy*vy; double b2=2*x*vx+2*y*vy; double c2=x*x+y*y-(Rm+r)*(Rm+r); double d1=b1*b1-4.0*a1*c1; double d2=b2*b2-4.0*a2*c2; double ansbig1=(-b1-sqrt(d1))/(2.0*a1); double ansbig2=(-b1+sqrt(d1))/(2.0*a1); double anssma1=(-b2-sqrt(d2))/(2.0*a2); double anssma2=(-b2+sqrt(d2))/(2.0*a2); if(d1<=eps) //与大圆相离 { puts("0.000"); } else if(ansbig2>=eps)//进入大圆 { if(d2<=eps) //最好的情况 { double ans=fabs(ansbig1-ansbig2); printf("%.3f ",ans); } else { double ans=fabs(ansbig1-ansbig2)-fabs(anssma1-anssma2); printf("%.3f ",ans); } } else //反向 进入时间为负 puts("0.000"); } return 0; }