HDU - 5572 An Easy Physics Problem (计算几何模板)
【题目概述】 On an infinite smooth table,there‘s a big round fixed cylinder and a little ball whose volume can be ignored. ? Currently the ball stands still at point A,then we‘ll give it an initial speed and a direction. If the ball hits the cylinder,it will bounce back with no energy losses. ? We‘re just curious about whether the ball will pass point B after some time. Input First line contains an integer T,which indicates the number of test cases. ? Every test case contains three lines. ? The first line contains three integers Ox,Oy and r,indicating the center of cylinder is (Ox,Oy) and its radius is r. ? The second line contains four integers Ax,Ay,Vx and Vy,indicating the coordinate of A is (Ax,Ay) and the initial direction vector is (Vx,Vy). ? The last line contains two integers Bx and By,indicating the coordinate of point B is (Bx,By). ? ? 1 ≤ T ≤ 100. ? ? |Ox|,|Oy|≤ 1000. ? ? 1 ≤ r ≤ 100. ? ? |Ax|,|Ay|,|Bx|,|By|≤ 1000. ? ? |Vx|,|Vy|≤ 1000. ? ? Vx≠0 or Vy≠0. ? ? both A and B are outside of the cylinder and they are not at same position. Output For every test case,you should output " Case #x: y",where x indicates the case number and counts from 1. y is " Yes" if the ball will pass point B after some time,otherwise y is " No". Sample Input 2 0 0 1 2 2 0 1 -1 -1 0 0 1 -1 2 1 -1 1 2 Sample Output Case #1: No Case #2: Yes ? 【题目大意】:一个面积无限大的光滑桌面,一个质点从初始点A(x0,y0)出发,初速度为(Vx,Vy),桌子上有一个圆柱体,圆心(cx,cy),半径为R,小球如果与圆柱体碰撞则发生的是完全弹性碰撞,在桌子上某处有一点B(ex,ey),问这个质点能不能经过B点? ? 【题解】:简单的几何学。记小球初始从A点沿着射线L1运动,分两种情况讨论。 (1)小球能和圆柱体相撞,即L1与圆O有两个交点(如果相切认为不会发生碰撞改变方向),记碰撞点为G点(射线与圆相交的较近的那一点),那么小球碰撞后沿什么射线运动呢?连接OG,则小球沿着L1关于OG的对称直线L2运动,如果B点在射线L2上则满足题意,或者在未碰撞之前,即B在线段AG上,也满足题意。 (2)小球不能与圆柱体相撞。判断B是否在射线L1上,若在则满足题意。 ? 【代码】 #include <algorithm> #include <cstdio> #include <vector> #include <cmath> using namespace std; const double eps = 1e-8; //1e-10会WA,注意调整精度,过大过小都不行 //浮点数是否等于0,在eps精度范围之内 int dcmp(double x){ if(fabs(x) < eps) return 0; return x < 0 ? -1 : 1; } //自定义开方 double mySqrt(double x){ return sqrt(max((double)0,x)); } //点的结构体定义 struct Point { double x,y; Point(double x=0,double y=0):x(x),y(y){} Point& operator = (Point p){ x = p.x; y = p.y; return *this; } }; typedef Point Vector; //向量四则运算定义 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);} //点乘定义 double dot(Vector A,Vector B){ return A.x * B.x + A.y * B.y;} //模长定义 double length(Vector A){ return mySqrt(dot(A,A));} //叉积定义 double cross(Vector A,Vector B){ return A.x * B.y - A.y * B.x;} //直线结构体 struct Line { //相当于点向式 // (x - x0) / v.x = (y - y0) / v.y Point p;//直线上一点 Vector v;//方向向量定方向 Line(Point p,Vector v):p(p),v(v){} Point getPoint(double t){ return Point(p.x + v.x*t,p.y + v.y*t); } }; //圆的结构体定义 圆心和半径即可 struct Circle { Point c; double r; Circle(Point c,double r):c(c),r(r){} }; //求圆和直线交点 ,返回1有两个实数解,其他返回0 int getLineCircleIntersection(Line L,Circle C,Point& P){ //返回t较小的那个点 double a = L.v.x; double b = L.p.x - C.c.x; double c = L.v.y; double d = L.p.y - C.c.y; double e = a*a + c*c; double f = 2*(a*b + c*d); double g = b*b + d*d - C.r*C.r; double delta = f*f - 4*e*g; //判别式大于0 一元二次方程才有实数解 if(dcmp(delta) <= 0) return 0; //一元二次方程求根公式 double t = (-f - mySqrt(delta)) / (2*e); P = L.getPoint(t); return 1; } int getLineCircleIntersection2(Line L,Point& P,Point& Q){ //返回两个点 double a = L.v.x; double b = L.p.x - C.c.x; double c = L.v.y; double d = L.p.y - C.c.y; double e = a*a + c*c; double f = 2*(a*b + c*d); double g = b*b + d*d - C.r*C.r; double delta = f*f - 4*e*g; //判别式大于0 一元二次方程才有两个实数解 if(dcmp(delta) < 0) return 0; //一元二次方程求根公式 double t1 = (-f - mySqrt(delta)) / (2*e); double t2 = (-f + mySqrt(delta)) / (2*e); P = L.getPoint(t1); Q = L.getPoint(t2); return 1; } //点是否在直线上 bool onLine(Point A,Line L){ Vector w = A - L.p; //printf("%lf %lfn",w.x,w.y); //叉积为0即共线 if(dcmp(cross(w,L.v)) == 0) return true; else return false; } bool onRay(Point A,Line L){//点A在射线L(p,v)上,不含端点 Vector w = A - L.p; //叉积等于0且点乘大于0 if(dcmp(cross(w,L.v))==0 && dcmp(dot(w,L.v)) > 0) return true; return false; } bool onSeg(Point A,Point B,Point C){//点A在线段BC上 //叉积等于0且点乘小于0 return dcmp(cross(B-A,C-A))==0 && dcmp(dot(B-A,C-A))<0; } Point project(Point A,Line L){ return L.p + L.v * ( dot(L.v,A - L.p) / dot(L.v,L.v) ); } //求点A关于直线L的对称点 Point mirrorPoint(Point A,Line L){ Vector D = project(A,L); //printf("project: %lf,%lfn",D.x,D.y); return D + (D - A); } int main() { int T; int ans = 0; double R; Point O,A,B; Vector V; /* A = Point(1,0); V = Point(1,1); Line L1 = Line(A,V); O.x = 2; O.y = 0; Circle yuanO = Circle(O,1); int tt = getLineCircleIntersection2( L1,yuanO,B); printf("%lf %lfn",A.x,A.y); printf("%lf %lfn",B.x,B.y); */ /* A = Point(1,1); Line l1 = Line(A,V); printf("%lf %lf %lf %lfn",l1.p.x,l1.p.y,l1.v.x,l1.v.y); B = Point(); while(scanf("%lf%lf",&B.x,&B.y) != EOF){ printf("%lf %lfn",B.y); printf("%dn",onLine( B,l1)); }*/ scanf("%d",&T); for(int ca = 1; ca <= T; ca++){ scanf("%lf%lf%lf",&O.x,&O.y,&R); scanf("%lf%lf%lf%lf",&A.x,&A.y,&V.x,&V.y); scanf("%lf%lf",&B.y); Line LA = Line(A,V); Circle yuanO = Circle(O,R); Point C; if(getLineCircleIntersection(LA,C)){ if(onSeg(B,C)) ans = 1; else{ //直线OC是对称轴 Line OC = Line(O,Vector(C.x - O.x,C.y - O.y)); Point A1 = mirrorPoint(A,OC); // printf("%lf,C.x,C.y); // printf("%lf,A1.x,A1.y); //射线CB Line CB = Line(C,Vector(B.x - C.x,B.y - C.y)); if(onRay(A1,CB)){ ans = 1; } else ans = 0; } }else{ if(onRay(B,LA)) ans = 1; else ans = 0; } printf("Case #%d: %sn",ca,ans ? "Yes" : "No"); } return 0; } (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |