HDU 4793 Collision(2013长沙区域赛现场赛C题)

题目链接: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
");
45             continue;
46         }
47         double V = v.len();
48         double D = get_dis(v,p);     //得到硬币到过原点的运动路线的距离
49 //        printf("%.3lf
",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
");
64             continue;
65         } 
66         printf("%lf
",2*ans+eps);
67     }
68     return 0;
69 }        
View Code
原文地址:https://www.cnblogs.com/xiaxiaosheng/p/4129807.html