HDU 5572 An Easy Physics Problem

淩亂°似流年 2022-04-15 07:06 272阅读 0赞

题目:点击打开链接 题意:二维平面中一位于(Ax, Ay)的点A以矢量v为方向运动,同时平面内有一半径为r 圆心为Ox Oy的圆,点A碰到圆就会反弹,问运动过程中是否能碰到点B。 分析:这题思路上并不难,写起来比较麻烦,抄的kuangbin的新板子,先判断一下直线AV是否与圆的交点个数,如果少于2个交点,判断B是否在射线AV上,如果有两个交点,求出距离A较近的那个交点P1,求出A关于QP1的对称点A1,判断B是否在线段AP1上或是否在射线P1A1上。

补充:这题不用long double也能过,用了保险一点,但是需要调一下eps,不能过大又不能过小,一般在1e-7至1e-8之间。计算几何模板很重要,精度也需要注意,代码比较长,包含注释。 代码:

  1. #include<algorithm>
  2. #include<iostream>
  3. #include<fstream>
  4. #include<complex>
  5. #include<cstdlib>
  6. #include<cstring>
  7. #include<cassert>
  8. #include<iomanip>
  9. #include<string>
  10. #include<cstdio>
  11. #include<bitset>
  12. #include<vector>
  13. #include<cctype>
  14. #include<cmath>
  15. #include<ctime>
  16. #include<stack>
  17. #include<queue>
  18. #include<deque>
  19. #include<list>
  20. #include<set>
  21. #include<map>
  22. using namespace std;
  23. #define pt(a) cout<<a<<endl
  24. #define debug test
  25. #define mst(ss,b) memset((ss),(b),sizeof(ss))
  26. #define rep(i,a,n) for (int i=a;i<=n;i++)
  27. #define per(i,a,n) for (int i=n-1;i>=a;i--)
  28. #define pii pair<int,int>
  29. #define fi first
  30. #define se second
  31. #define ll long long
  32. #define ull unsigned long long
  33. #define ld long double
  34. const ld eps = 1e-10;
  35. const ld inf = 1e20;
  36. const ld pi = acos(-1.0);
  37. const int maxp = 1010;
  38. int sgn(ld x){
  39. if(fabs(x) < eps)return 0;
  40. if(x < 0)return -1;
  41. else return 1;
  42. }
  43. struct Point{
  44. ld x,y;
  45. Point(){}
  46. Point(ld _x,ld _y){
  47. x = _x;
  48. y = _y;
  49. }
  50. Point operator - (const Point &b)const{
  51. return Point(x-b.x,y-b.y);
  52. }
  53. //叉积
  54. ld operator ^(const Point &b)const{
  55. return x*b.y - y*b.x;
  56. }
  57. //点积
  58. ld operator *(const Point &b)const{
  59. return x*b.x + y*b.y;
  60. }
  61. //返回长度
  62. ld len(){
  63. return hypot(x,y);//库函数
  64. }
  65. //返回长度的平方
  66. ld len2(){
  67. return x*x + y*y;
  68. }
  69. //返回两点的距离
  70. ld distance(Point p){
  71. return hypot(x-p.x,y-p.y);
  72. }
  73. Point operator +(const Point &b)const{
  74. return Point(x+b.x,y+b.y);
  75. }
  76. Point operator *(const ld &k)const{
  77. return Point(x*k,y*k);
  78. }
  79. Point operator /(const ld &k)const{
  80. return Point(x/k,y/k);
  81. }
  82. //化为长度为 r 的向量
  83. Point trunc(ld r){
  84. ld l = len();
  85. if(!sgn(l))return *this;
  86. r /= l;
  87. return Point(x*r,y*r);
  88. }
  89. };
  90. struct Line{
  91. Point s,e;
  92. Line(){}
  93. Line(Point _s,Point _e){
  94. s = _s;
  95. e = _e;
  96. }
  97. //求线段长度
  98. ld length(){
  99. return s.distance(e);
  100. }
  101. //返回直线倾斜角 0<=angle<pi
  102. ld angle(){
  103. ld k = atan2(e.y-s.y,e.x-s.x);
  104. if(sgn(k) < 0)k += pi;
  105. if(sgn(k-pi) == 0)k -= pi;
  106. return k;
  107. }
  108. //点和直线关系
  109. //1 在左侧
  110. //2 在右侧
  111. //3 在直线上
  112. int relation(Point p){
  113. int c = sgn((p-s)^(e-s));
  114. if(c < 0)return 1;
  115. else if(c > 0)return 2;
  116. else return 3;
  117. }
  118. //点到直线的距离
  119. ld dispointtoline(Point p){
  120. return fabs((p-s)^(e-s))/length();
  121. }
  122. // 点在线段上的判断
  123. bool pointonseg(Point p){
  124. return sgn((p-s)^(e-s)) == 0 && sgn((p-s)*(p-e)) <= 0;
  125. }
  126. //返回点 p 在直线上的投影
  127. Point lineprog(Point p){
  128. return s + ( ((e-s)*((e-s)*(p-s)))/((e-s).len2()) );
  129. }
  130. //返回点 p 关于直线的对称点
  131. Point symmetrypoint(Point p){
  132. Point q = lineprog(p);
  133. return Point(2*q.x-p.x,2*q.y-p.y);
  134. }
  135. };
  136. struct circle{
  137. Point p;//圆心
  138. ld r;//半径
  139. circle(Point _p,ld _r){
  140. p = _p;
  141. r = _r;
  142. }
  143. //直线和圆的关系
  144. //比较的是圆心到直线的距离和半径的关系
  145. int relationline(Line v){
  146. ld dst = v.dispointtoline(p);
  147. if(sgn(dst-r) < 0)return 2;
  148. else if(sgn(dst-r) == 0)return 1;
  149. return 0;
  150. }
  151. //求直线和圆的交点,返回交点个数
  152. int pointcrossline(Line v,Point &p1,Point &p2){
  153. if(!(*this).relationline(v))return 0;
  154. Point a = v.lineprog(p);
  155. ld d = v.dispointtoline(p);
  156. d = sqrt(r*r-d*d);
  157. if(sgn(d) == 0){
  158. p1 = a;
  159. p2 = a;
  160. return 1;
  161. }
  162. p1 = a + (v.e-v.s).trunc(d);
  163. p2 = a - (v.e-v.s).trunc(d);
  164. return 2;
  165. }
  166. };
  167. int t,r;
  168. Point Q,A,B,V;
  169. int main() {
  170. cin>>t;
  171. for(int cas=1;cas<=t;cas++) {
  172. cin>>Q.x>>Q.y>>r;
  173. cin>>A.x>>A.y>>V.x>>V.y;
  174. cin>>B.x>>B.y;
  175. V=Point(A.x+V.x,A.y+V.y);
  176. Line LA=Line(A,V);
  177. circle O = circle(Q,r);
  178. Point P1,P2;
  179. int cnt = O.pointcrossline(LA,P1,P2);
  180. int f=0;
  181. if(cnt==0||cnt==1) {
  182. ///如果圆和向量(直线)AV少于两个交点,直接判断点B是否在射线AV上
  183. if(LA.relation(B) == 3 && sgn((V-A)*(B-A)) > 0 ) f=1;
  184. }else {
  185. ///否则先判断点B是否在线段AP1上,再判断是否在射线P1A1上,A1为点A关于直线QP1(圆的半径)的对称点
  186. if(sgn(A.distance(P1)-A.distance(P2)) >0 ) P1=P2;///P1为第一个交点(较近的点)
  187. Line QP1=Line(Q,P1);
  188. Line AP1=Line(A,P1);
  189. Point A1=QP1.symmetrypoint(A);
  190. if( AP1.pointonseg(B)) f=1;
  191. Line P1A1=Line(P1,A1);
  192. if( P1A1.relation(B) == 3 && sgn((A1-P1)*(B-P1)) > 0 ) f=1;
  193. }
  194. cout<<"Case #"<<cas<<": ";
  195. if(f) cout<<"Yes"<<endl;
  196. else cout<<"No"<<endl;
  197. }
  198. return 0;
  199. }

发表评论

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

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

相关阅读