题目大意:
有一个圆形奖章固定在一个光滑桌面,我们抛出一些硬币,让它们朝着奖章碰撞。还有一个圆形范围内,圆形范围与奖章有同样的圆心,圆形奖章严格小于圆形范围半径。假设硬币碰撞奖章时不损失能量,然后镜面反射移动方向。
假设圆奖牌和圆范围的圆心是(0,0),硬币的初始位置是严格在圆外的。奖章半径Rm,硬币半径r,则圆范围半径R,初始位置(x,y)和初始速度矢量硬币(Vx,Vy)的半径。请计算硬币的任意部分在圆形范围内的总时间。
【分析】
(吐槽:翻译好累啊。。。。)
题目其实很简单,我们可以简单分为三种情况。
1.硬币不进入范围,输出0;
2.硬币进入范围,与奖章碰撞
3.进入范围,不碰撞
只要确定了是哪种情况,剩余的在草稿纸上画画就可以得到答案了。
区分1与2.3时。我们令点P为硬币的圆心,令Q=P+1000*V,于是Q便是P走了1000个单位时间的位置。
我们判断Vector(OP) Dot Vector(QP) 的正负,如果非正,那么为情况1。
我们求得点O(0,0)与直线VP的距离为OVP。如果OVP>(R+r),那么同样不进入范围,为情况1.
区分2与3时。如果OVP>(Rm+r),为情况3,否则为情况2.
剩下的就用勾股定理即可解决。
【代码】
/***********************
ID:Ciocio
LANG:C++
DATE:2014-1-21
TASK:Collision
************************/
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;
#define sqr(x) ((x)*(x))
double Rm,R,r;
struct Point{
double x,y;
Point(double x=0,double y=0):x(x),y(y){}
};
typedef Point Vector;
Point P;
Point O=Point(0,0);
Vector V;
Vector operator + (Vector A,Vector B)
{return Vector(A.x+B.x,A.y+B.y);}
Vector operator - (Point A,Point B)
{return Vector(A.x-B.x,A.y-B.y);}
Vector operator * (Vector A,double p)
{return Vector(A.x*p,A.y*p);}
Vector operator / (Vector A,double p)
{return Vector(A.x/p,A.y/p);}
bool operator < (const Point &a,const Point &b)
{return a.x<b.x||(a.x==b.x&&a.y<b.y);}
const double eps=1e-10;
int dcmp(double x){if(fabs(x)<eps) return 0;else return x<0?-1:1;}
bool operator == (const Point &a,const Point &b)
{return dcmp(a.x-b.x)==0&&dcmp(a.y-b.y)==0;}
double Dot(Vector A,Vector B)
{return A.x*B.x+A.y*B.y;}
double Cross(Vector A,Vector B)
{return A.x*B.y-A.y*B.x;}
double Length(Vector A){return sqrt(Dot(A,A));}
Vector Normal(Vector A)
{double L=Length(A);
return Vector(-A.y/L,A.x/L);}
double Dis(Point A,Point B)
{return sqrt(sqr(A.x-B.x)+sqr(A.y-B.y));}
void _init()
{
scanf("%lf%lf",&P.x,&P.y);
scanf("%lf%lf",&V.x,&V.y);
}
void _solve()
{
Vector Q=P+Vector(V.x*1000,V.y*1000);
if(Dot(P-Q,P-O)<=0) //OP.QP
{
printf("0.000\n");
return;
}
double OVP=fabs(Cross(P-Q,P-O)/Length(P-Q)); //the distance of point O and line VP
double len1=sqrt(sqr(R+r)-sqr(OVP));
double len2=len1-(sqrt(sqr(Rm+r)-sqr(OVP)));
if(OVP>(R+r)) //if the coin is not going through the range
{
printf("0.000\n");
return;
}
if(OVP>(Rm+r)) printf("%.3lf\n",2*len1/Length(V)); //not impact
else printf("%.3lf\n",2*len2/Length(V)); //impact
}
int main()
{
while(scanf("%lf%lf%lf",&Rm,&R,&r)!=EOF)
{
_init();
_solve();
}
return 0;
}