题目链接
题意:
给一个以(0,0)为圆心半径为R的圆形区域,中间放着一个(0,0)为圆心半径为Rm的圆盘,在坐标(x,y)处(严格在圆形区域外)放着一枚半径为r的硬币,运动方向和速度为(vx,vy),在运动中碰到圆盘时,会按碰撞问题反弹(圆盘是固定不动的),问硬币会在圆形区域里呆多长时间(硬币只要有一点点在圆形区域里就记为硬币在圆形区域内)。
思路:
差点就过了写残了.
假设我们设圆心到运动方向直线的最短距离为d,
那么如果d >= R + r 那么结果为0.
如果d>= Rm+r && d < R + r 那么一定不和中间小圆相撞,直接穿过大圆.那么距离就是直线与大圆的弦长,可以勾股定理.再除以速度即可
剩下的就是d <= Rm+r。 画个图就可以发现,当和大圆相切和小圆相切,走过的距离为大圆和coin到圆心到直线垂线交点的距离-小圆的.(也是勾股定理,因为反弹情况一样,所以直接二倍再除以速度即可)
PS : 另外如果上来速度反向相反,永远不可能到达,速度也为0.这个过程可以看成从coin圆心到原点的一个向量,,和圆心的速度向量的点积来判断,如果 >0 则同向,否则反向
#include
using namespace std;
const double eps =1e-8;
int sgn(double x)
{
if(fabs(x)0) return 1;
return -1;
}
int main()
{
double Rm, R, r, x, y, vx ,vy;
double d,A,B,C,at,lk,ans;
while(~scanf("%lf%lf%lf%lf%lf%lf%lf",&Rm, &R, &r, &x, &y, &vx ,&vy))
{
A=vy;
B=-vx;
C=vx*y-vy*x;
d=fabs(C/sqrt(A*A+B*B));
if( sgn((-y)*vy-x*vx) <=0 ) ans=0;//向量点积
else if( sgn(d-(R+r)) >=0) ans=0;
else if( sgn(d-(Rm+r))>=0 )
{
at=sqrt((R+r)*(R+r)-d*d);
ans= (2.0*at)/sqrt(vx*vx+vy*vy);
}
else
{
at=sqrt((Rm+r)*(Rm+r)-d*d);
lk=R+r;
lk=sqrt(lk*lk- d*d);
lk-=at;
ans=(2.0*lk)/sqrt(vx*vx+vy*vy);
}
printf("%.6lf\n",ans);
}
return 0;
}
/*
已知两向量的坐标 如何判断他们是同向还是反向
对两向量做点乘,若结果大于0,就是同向,等于0垂直,小于0反向
如a(x1,y1),b(x2,y2)
a*b=x1*x2+y1*y2;
判断a*b的符号就可以了*/