There’s a round medal fixed on an ideal smooth table, Fancy is trying to throw some coins and make
them slip towards the medal to collide. There’s also a round range which shares exact the same center
as the round medal, and radius of the medal is strictly less than radius of the round range. Since that
the round medal is fixed and the coin is a piece of solid metal, we can assume that energy of the coin
will not lose, the coin will collide and then moving as reflect.
Now assume that the center of the round medal and the round range is origin (Namely (0, 0)) and
the coin’s initial position is strictly outside the round range. Given radius of the medal Rm, radius of
coin r, radius of the round range R, initial position (x, y) and initial speed vector (vx, vy) of the coin,
please calculate the total time that any part of the coin is inside the round range.
Please note that the coin might not even touch the medal or slip through the round range.
Input
There will be several test cases. Each test case contains 7 integers Rm, R, r, x, y, vx and vy in one
line. Here 1 ≤ Rm < R ≤ 2000, 1 ≤ r ≤ 1000, R + r < |(x, y)| ≤ 20000, 1 ≤ |(vx, vy)| ≤ 100.
Output
For each test case, please calculate the total time that any part of the coin is inside the round range.
Please output the time in one line, an absolute error not more than 1e-3 is acceptable.
Sample Input
5 20 1 0 100 0 -1
5 20 1 30 15 -1 0
Sample Output
30.000
29.394
大致题意:在光滑的桌面上固定了一个半径为Rm的圆盘,圆心在坐标(0,0)处,有一个半径为R圆心也在(0,0)的圆形范围。现在在这个圆形范围外有一个半径为r的圆形硬币,告诉你它的圆心坐标和速度矢量,问这个圆形硬币在这个圆形范围内经过的时间,如果与中心圆盘相撞,那么会以相同的速度原路返回。
思路:已知硬币的圆心坐标和它的速度矢量,所以我们可以很容易的求出硬币圆心的运动直线方程,假设直线方程为y=k*x+b,那么k=vy/vx,b=y0-k*x0。然后我们求下硬币与圆形范围相切时候的硬币圆心的坐标,即找出该直线上的点(x,y)使得它到点(0,0)的距离为(R+r),列个方程解下就可以了,如果有解的话会是两个坐标,如果无解的话则说明不经过。接着我们判断下这两个坐标与起始坐标之间的大小关系,判断是否满足速度矢量,如果不满足说明也不经过。然后接着按照相同的方法求硬币与圆盘相切时的硬币圆心坐标。如果无解,说明硬币是直接从圆形范围内穿过,那么所花时间即之前所求得的两个相切点之间的的距离除以速度,如果有解,则说明硬币会和它相撞,然后按原路返回,所花时间即离起点最近的两个切点(一个圆形范围的切点,一个圆盘的切点)间的距离除以速度乘再2。
代码如下
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <queue>
#include <cmath>
#include <cstring>
using namespace std;
int R1,R2,r,x,dx,y,dy;
double max(double q1,double q2)
{
if(q1>q2) return q1;
else return q2;
}
double min(double q1,double q2)
{
if(q1<q2) return q1;
else return q2;
}
int main()
{
while(scanf("%d%d%d%d%d%d%d",&R1,&R2,&r,&x,&y,&dx,&dy)!=EOF)
{
if(dx!=0)//考虑下直线斜率是否存在,如果存在
{
double k=dy*1.0/dx;
double b=y-k*x;
double ans=((R2+r)*(R2+r)+k*k*b*b/(k*k+1)-b*b)/(k*k+1);
if(ans<=0)//如果无解
{
printf("0.000\n");
continue;
}
ans=sqrt(ans);
double a1=ans-k*b/(k*k+1);
double a2=-ans-k*b/(k*k+1);
double x1=max(a1,a2);
double x2=min(a1,a2);
if(dx>0&&x>x1)//判断下两个切点坐标和起点之间的大小关系是否满足速度矢量
{
printf("0.000\n");
continue;
}
if(dx<0&&x<x2)
{
printf("0.000\n");
continue;
}
double ans2=((R1+r)*(R1+r)+k*k*b*b/(k*k+1)-b*b)/(k*k+1);
if(ans2<=0)//如果无解,说明硬币没有碰撞上圆盘,直接从圆形范围中穿出
{
if(dx<0)
dx=-dx;
printf("%.3lf\n",(x1-x2)/dx);
}
else
{
ans2=sqrt(ans2);
a1=ans2-k*b/(k*k+1);
a2=-ans2-k*b/(k*k+1);
double x3=max(a1,a2);
double x4=min(a1,a2);
if(dx<0)
printf("%.3lf\n",-2*(x1-x3)/dx);
else
printf("%.3lf\n",2*(x4-x2)/dx);
}
}
else //如果直线斜率不存在
{
double ans=(R2+r)*(R2+r)-x*x;
if(ans<=0)
{
printf("0.000\n");
continue;
}
double y1=sqrt(ans);
double y2=-sqrt(ans);
if(dy<0&&y<y1)
{
printf("0.000\n");
continue;
}
if(dy>0&&y>y1)
{
printf("0.000\n");
continue;
}
double ans2=(R1+r)*(R1+r)-x*x;
if(ans2<=0)
{
if(dy<0)
dy=-dy;
printf("%.3lf\n",(y1-y2)/dy);
}
else
{
double y3=sqrt(ans2);
double y4=-sqrt(ans2);
if(dy<0)
printf("%.3lf\n",-2*(y1-y3)/dy);
else
printf("%.3lf\n",2*(y4-y2)/dy);
}
}
}
return 0;
}