近来比较流行几何的碰撞问题。解析几何在其中就发挥着非常大的作用。解析几何一般模板较多,代码非常长,并有可能牵系到旋转,对称,求交点,反射等实复杂模拟。不仅需要个人思路清晰,步步为营,更需要对模板有着炉火纯青的掌握与使用。
Problem : 3834 ( Where am I ) :
这是前几天HDoj比赛中的一道解析几何题,当初刚接触几何,有点想法,但不知如何下手。昨天重拾此题,但由于对解析几何的模板不熟悉,花了大半天时间还没有做出这个题。今天晚饭前百度了下,看懂了(自己对模板,向量,极坐标的理解还不够深入)。睡前花了一个小时AC之。(粘贴+敲代码用了半个小时,一步步查找错误用了半个小时。)
View Code
Problem : 3834 ( Where am I ) Judge Status : Accepted
RunId : 4247553 Language : C++ Author : ccsu2009021212
Code Render Status : Rendered By HDOJ C++ Code Render Version 0.01 Bet
RunId : 4247553 Language : C++ Author : ccsu2009021212
Code Render Status : Rendered By HDOJ C++ Code Render Version 0.01 Bet
#include <cmath > #include<iostream> #include<stdio.h> using namespace std; /* 常用的常量定义 */ const double INF = 1E200; const double EP = 1E-10; const int MAXV = 300; const double PI = acos(-1.0); struct POINT { double x; double y; POINT(double a=0, double b=0) { x=a; y=b;} //constructor }; struct LINESEG { POINT s; POINT e; LINESEG(POINT a, POINT b) { s=a; e=b;} LINESEG() { } }; struct LINE // 直线的解析方程 a*x+b*y+c=0 为统一表示,约定 a >= 0 { double a; double b; double c; LINE(double d1=1, double d2=-1, double d3=0) {a=d1; b=d2; c=d3;} }; LINE getline(POINT p1,POINT p2) { LINE tl; int sign = 1; tl.a=p2.y-p1.y; if(tl.a<0) { sign = -1; tl.a=sign*tl.a; } tl.b=sign*(p1.x-p2.x); tl.c=sign*(p1.y*p2.x-p1.x*p2.y); return tl; } double dist(POINT p1,POINT p2) { return( sqrt( (p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y) ) ); } bool equal_point(POINT p1,POINT p2) // 判断两个点是否重合 { return ( (abs(p1.x-p2.x)<EP)&&(abs(p1.y-p2.y)<EP) ); } int clpoint(POINT p,double r,double a,double b,double c,POINT &rp1,POINT &rp2) { int res=0; c=c+a*p.x+b*p.y; double tmp; if(a==0&&b!=0) { tmp=-c/b; if(r*r<tmp*tmp) res=0; else if(r*r==tmp*tmp) { res=1; rp1.y=tmp; rp1.x=0; } else { res=2; rp1.y=rp2.y=tmp; rp1.x=sqrt(r*r-tmp*tmp); rp2.x=-rp1.x; } } else if(a!=0&&b==0) { tmp=-c/a; if(r*r<tmp*tmp) res=0; else if(r*r==tmp*tmp) { res=1; rp1.x=tmp; rp1.y=0; } else { res=2; rp1.x=rp2.x=tmp; rp1.y=sqrt(r*r-tmp*tmp); rp2.y=-rp1.y; } } else if(a!=0&&b!=0) { double delta; delta=b*b*c*c-(a*a+b*b)*(c*c-a*a*r*r); if(delta<0) res=0; else if(delta==0) { res=1; rp1.y=-b*c/(a*a+b*b); rp1.x=(-c-b*rp1.y)/a; } else { res=2; rp1.y=(-b*c+sqrt(delta))/(a*a+b*b); rp2.y=(-b*c-sqrt(delta))/(a*a+b*b); rp1.x=(-c-b*rp1.y)/a; rp2.x=(-c-b*rp2.y)/a; } } rp1.x+=p.x; rp1.y+=p.y; rp2.x+=p.x; rp2.y+=p.y; return res; } double angle(POINT o,POINT s,POINT e) { double cosfi,fi,norm; double dsx = s.x - o.x; double dsy = s.y - o.y; double dex = e.x - o.x; double dey = e.y - o.y; cosfi=dsx*dex+dsy*dey; norm=(dsx*dsx+dsy*dsy)*(dex*dex+dey*dey); cosfi /= sqrt( norm ); if (cosfi >= 1.0 ) return 0; if (cosfi <= -1.0 ) return -3.1415926; fi=acos(cosfi); if (dsx*dey-dsy*dex>0) return fi; // 说明矢量os 在矢量 oe的顺时针方向 return -fi; } POINT rotate(POINT v,POINT o,double angle,double scale)// { POINT ret=o; v.x-=o.x,v.y-=o.y; o.x=scale*cos(angle); o.y=scale*sin(angle); ret.x+=v.x*o.x-v.y*o.y; ret.y+=v.x*o.y+v.y*o.x; return ret; } int main() { int tt; scanf("%d",&tt); while(tt--) { POINT o,s,e; double r,r1,dx,dy,t; scanf("%lf%lf%lf",&o.x,&o.y,&r); scanf("%lf%lf%lf",&s.x,&s.y,&r1); scanf("%lf%lf%lf",&dx,&dy,&t); r-=r1; e.x=s.x+dx;e.y=s.y+dy; LINE l1=getline(s,e); POINT x,y,cur; clpoint(o,r,l1.a,l1.b,l1.c,x,y); if((dx>0 && x.x>y.x)||(dx<0 && x.x<y.x)||(dy>0 && x.y>y.y)||(dy<0 && x.y<y.y)); else{cur=x,x=y,y=cur;} double left=dist(x,s); if(left>=sqrt(dx*dx+dy*dy)*t) { printf("%.1lf %lf.1\n",s.x+t*dx,s.y+t*dy); continue; } t=sqrt(dx*dx+dy*dy)*t; t-=left; double rad=angle(o,x,y); double len=fabs(r*sin(rad/2)*2); double turn=floor(t/len); left=t-turn*len; POINT now1,now2; rad*=-1; now1=rotate(x,o,rad*turn,1.0); now2=rotate(x,o,rad*(turn+1),1.0); POINT ret; ret.x=now1.x+(now2.x-now1.x)*left/len; ret.y=now1.y+(now2.y-now1.y)*left/len; printf("%.1lf %.1lf\n",ret.x,ret.y); } }