HDU - 5572 An Easy Physics Problem(计算几何)

朱雀 2022-06-07 07:47 231阅读 0赞

点我看题

题意:一个点A(ax,ay)沿着某个方向(vx,vy)移动,有一个圆心为O(ox,oy)半径为r的圆,若点撞到圆会反弹且没有能量损失,问在这个点的行走过程中,能不能经过点B(bx,by).

分析:拿到题目就想到扥两种情况,①没有撞到圆;②撞到圆

对于没有撞到圆的情况,只要判断一直往下走的过程中是否会经过点B;

如果撞到圆,就要看在撞到圆之前是否会经过B,不经过的话,看反弹之后会不会经过B.

//设入射线的极角方程为x=vx*t+ax,y=vy*t+ay
//圆的方程为(x-ox)^2+(y-oy)^2 = r^2
//联立两个方程组得到(vx^2+vy^2)*t^2+2*((ax-ox)*vx+(ay-oy)*vy)*t+((ax-ox)^2+(ay-oy)^2-r^2) = 0

首先联立直线(用极角方程)与圆的方程,看delta是否大于0,如果大于0且b小于0(两根都要大于0的,即-b/a>0),求出较小的t(想想为什么),然后求出交点,接着可以求出切线方程(emmm自己求得是法线结果wa了好久),再求出B点关于切线方程的反对称点C,看C是否在A的射线上.

参考代码:

  1. /*计算几何*/
  2. #include<cstdio>
  3. #include<cmath>
  4. #include<cstring>
  5. #include<algorithm>
  6. #include<iostream>
  7. using namespace std;
  8. #define eps 1e-8
  9. double ox,oy,r;
  10. double ax,ay,vx,vy;
  11. double bx,by;
  12. int sgn( double x)
  13. {
  14. if( fabs(x) < eps)
  15. return 0;
  16. if( x > 0)
  17. return 1;
  18. return -1;
  19. }
  20. inline double sqr( double x)
  21. {
  22. return x*x;
  23. }
  24. int main()
  25. {
  26. int T;
  27. scanf("%d",&T);
  28. while( T--)
  29. {
  30. scanf("%lf%lf%lf",&ox,&oy,&r);
  31. scanf("%lf%lf%lf%lf",&ax,&ay,&vx,&vy);
  32. scanf("%lf%lf",&bx,&by);
  33. static int cas = 1;
  34. printf("Case #%d: ",cas++);
  35. //设入射线的极角方程为x=vx*t+ax,y=vy*t+ay
  36. //圆的方程为(x-ox)^2+(y-oy)^2 = r^2
  37. //联立两个方程组得到(vx^2+vy^2)*t^2+2*((ax-ox)*vx+(ay-oy)*vy)*t+((ax-ox)^2+(ay-oy)^2-r^2) = 0
  38. double a = sqr(vx)+sqr(vy);
  39. double b = 2*((ax-ox)*vx+(ay-oy)*vy);
  40. double c = sqr(ax-ox)+sqr(ay-oy)-sqr(r);
  41. //delta大于0,表示有两个根,-b/2a>0(使方程有两个正根)
  42. if( sgn( b*b-4*a*c) > 0 && sgn(b) < 0)
  43. {
  44. double tp = (-b-sqrt(b*b-4*a*c))/(2.0*a);//取较小的根,因为第一个交点肯定距离A点近一点
  45. double px = vx*tp+ax;//入射线与圆的交点
  46. double py = vy*tp+ay;
  47. //判断B是否在入射线上
  48. if( vx != 0)
  49. {
  50. double t = (bx-ax)/vx;
  51. if( sgn(by-vy*t-ay) == 0 && sgn(t-tp) <= 0)
  52. {
  53. puts("Yes");
  54. continue;
  55. }
  56. }
  57. else if( vy != 0)
  58. {
  59. double t = (by-ay)/vy;
  60. if( sgn(bx-vx*t-ax) == 0 && sgn(t-tp) <= 0)
  61. {
  62. puts("Yes");
  63. continue;
  64. }
  65. }
  66. //求切线方程Ax+By+C=0
  67. double A = px-ox;
  68. double B = py-oy;
  69. double C = (ox-px)*px+(oy-py)*py;
  70. //求B点关于法线的反对称点
  71. double cx = bx-2.0*A*(A*bx+B*by+C)/(sqr(A)+sqr(B));
  72. double cy = by-2.0*B*(A*bx+B*by+C)/(sqr(A)+sqr(B));
  73. if( sgn(vx) != 0)
  74. {
  75. double t = (cx-ax)/vx;
  76. if( sgn(cy-vy*t-ay) == 0 && sgn(t) > 0)//>0???
  77. puts("Yes");
  78. else
  79. puts("No");
  80. }
  81. else if( sgn(vy) != 0)
  82. {
  83. double t = (cy-ay)/vy;
  84. if( sgn(cx-vx*t-ax) == 0 && sgn(t) > 0)
  85. puts("Yes");
  86. else
  87. puts("No");
  88. }
  89. }
  90. else//射线
  91. {
  92. if( sgn(vx) != 0)
  93. {
  94. double t = (bx-ax)/vx;
  95. if( sgn(by-vy*t-ay) == 0 && sgn(t) > 0)
  96. puts("Yes");
  97. else
  98. puts("No");
  99. }
  100. else if( sgn(vy) != 0)
  101. {
  102. double t = (by-ay)/vy;
  103. if( sgn(bx-vx*t-ax) == 0 && sgn(t) > 0)
  104. puts("Yes");
  105. else
  106. puts("No");
  107. }
  108. }
  109. }
  110. return 0;
  111. }

发表评论

表情:
评论列表 (有 0 条评论,231人围观)

还没有评论,来说两句吧...

相关阅读