题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4793
解题报告:在一个平面上有一个圆形medal,半径为Rm,圆心为(0,0),同时有一个圆形范围圆心也是(0,0),半径为R,R > Rm,现在向平面上投掷一枚硬币,硬币初始的圆心位置为(x,y),半径是r,给出硬币的速度向量,硬币碰到medal的时候会反射,注意,反射就是原路返回,并不是按照常理的按照圆心连线的路线,表示一直以为是这样,WA了很久,然后,让你求硬币跟圆形范围有交集的时候的总时间是多少。
首先,过原点,作一条与速度向量平行的直线l,然后求出(x,y)到直线l的距离D,然后通过一系列勾股定理就可以求出路程。值得注意的就是有几种情况要特判。
第一,速度的方向跟(x,y)与原点的连线的向量的夹角是不是[0,90)的范围,然后满足这个条件之后还要判断,当D > R+r时,硬币会直接过去而不会经过圆形范围,所以时间直接是0,当Rm+r < D < R+r时,硬币会经过圆形范围,但不会跟medal有碰撞,当D < Rm+r时,硬币跟medal有碰撞。
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #include<cmath> 6 using namespace std; 7 const double eps = 1e-8,PI = acos(-1.0); 8 9 struct point 10 { 11 double x,y; 12 point(double x = 0,double y = 0) :x(x),y(y){} 13 double len() 14 { 15 return sqrt(x*x+y*y+eps); 16 } 17 }; 18 inline double dis(point p1,point p2) 19 { 20 return sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y)+eps); 21 } 22 double get_dis(point v,point p) 23 { 24 if(fabs(v.x*p.y - p.x*v.y) < eps) return 0; 25 double si = (v.x*p.y-p.x*v.y)/dis(point(0,0),v)/p.len(); 26 return p.len() * fabs(si); 27 } 28 int judge(point p,point v) 29 { 30 point temp; 31 temp.x = -1 * p.x; 32 temp.y = -1 * p.y; 33 return (temp.x*v.x+temp.y*v.y < 0) || (fabs(temp.x*v.x+temp.y*v.y) <eps); 34 } 35 int main() 36 { 37 // freopen("in.txt","r",stdin); 38 double Rm,R,r; 39 point p,v; 40 while(scanf("%lf%lf%lf%lf%lf%lf%lf",&Rm,&R,&r,&p.x,&p.y,&v.x,&v.y)!=EOF) 41 { 42 if(judge(p,v)) 43 { 44 printf("0.0000\n"); 45 continue; 46 } 47 double V = v.len(); 48 double D = get_dis(v,p); //得到硬币到过原点的运动路线的距离 49 // printf("%.3lf\n",D); 50 double ans = 0; 51 if(D < Rm+r) //会碰撞,坑,这种情况下题目的反射违反了常理,一直wa在这里 52 { 53 double l = sqrt((R+r)*(R+r)-D*D+eps) - sqrt((Rm+r)*(Rm+r)-D*D+eps); //进入圈开始到碰撞走过的距离 54 ans += (l / V); 55 // ans += (R - Rm) / V; 56 } 57 else if(D > Rm+r && D < R + r) 58 { 59 double t = sqrt((R+r)*(R+r) - D*D+eps) / V; 60 } 61 else //不会进入圆形范围 62 { 63 printf("0.00000\n"); 64 continue; 65 } 66 printf("%lf\n",2*ans+eps); 67 } 68 return 0; 69 }
时间: 2024-10-16 18:19:29