HDU6798
http://acm.hdu.edu.cn/showproblem.php?pid=6798
参考博客 >https://www.cnblogs.com/stelayuri/p/13393651.html
大致题意:给定等边三角形的三个点,内有一动点,给定动点的速度向量,点与三角形边碰撞以镜面反射的角度改变方向,速度不变,求经过k次碰撞的时间。
分析;二分时间进行判断,碰撞可以看出无限个三角形进行拼接的二维平面,对于一个点移动形成的射线,与直线所经过的点数。(二维平面镜面碰撞问题)
预处理三种坐标系,分别是以AB,AC,BC为X坐标轴,动点的速度向量。然后根据 求交点。具体三种坐标视图.引用上述大佬博客的图。(水印抱歉
BC为X坐标轴。
当点往BC的下端移动时,计算答案时候要加上BC这条边。
AB为X坐标轴(BC同理)
当点往AB的下端移动时,计算答案时候要加上AB这条边。
#include<bits/stdc++.h> using namespace std; using namespace std; typedef long long ll; typedef double db; const db eps=1e-6; const db PI=acos(-1.0); const int maxn=5e3+10; int n; inline db readb() { int f=1;db x=0;char s=getchar(); for( ;!isdigit(s);s=='-' && (f=-1),s=getchar()); for( ;isdigit(s);x=x*10+s-48,s=getchar()); if( s=='.' ) for( db l=0.1,s=getchar();isdigit(s);x=x+(s-48)*l,l/=10,s=getchar() ); return x*f; } int sgn( double d ) { return (d>eps)-(d<-eps); }; // 精度判断 struct point{ db x,y; point(){ x=y=0; } point(db _x,db _y ){ x=_x,y=_y; } point operator + ( const point &rhs ) const { return point(x+rhs.x,y+rhs.y); } point operator - ( const point &rhs ) const { return point(x-rhs.x,y-rhs.y); } point operator / ( const int &rhs ) const { return point(x/rhs,y/rhs); } db operator * ( const point &rhs ) const { return 1ll*x*rhs.y-1ll*y*rhs.x; } db dot( const point &rhs ) const { return 1ll*x*rhs.x+1ll*y*rhs.y; } void get(){ x=readb(),y=readb(); } bool operator == ( const point &rhs ) const { return x==rhs.x && y==rhs.y; } bool operator < ( const point &rhs ) const { return sgn(x-rhs.x)<0 || sgn(x-rhs.x)==0 && sgn(y-rhs.y)<0 ; } point Rotate( db rad ) { return point(x*cos(rad)-y*sin(rad), x*sin(rad)+y*cos(rad) ); } // bool operator < ( const point &rhs ) const { return (*this)*rhs>0 ; } 极角排序 }; db dist( point a,point b ) { return sqrt( (b-a).dot(b-a) ); } //--------------------直线---------------- struct sLine{ // 直线 point s,e; sLine(){} sLine( point _s,point _e ) { s=_s,e=_e; } pair<point,int> operator & ( const sLine &rhs ) const{ // 两直线相交问题 point res=s; //交点 if( sgn( (s-e)*(rhs.s-rhs.e) )==0 ) { if( sgn( (rhs.s-s)*(rhs.e-s) )==0 ) return make_pair(res,0); // 两直线重合 else return make_pair( res,1 ); // 两直线平行 } db t= ( (s-rhs.s)*(rhs.s-rhs.e) )/ ( (s-e)*(rhs.s-rhs.e) ) ; //单位化 res.x+=(e.x-s.x)*t; res.y+=(e.y-s.y)*t; return make_pair(res,2); // 有交点 } db getDistance( point A ) //点到直线的距离 { return fabs((A-s)*(A-e)/dist(s,e) ); } }; db L,x,y,vx,vy,h; int k; point A,B,C,oripot,v1,v2,v3; sLine AB,AC,BC; bool check( db tim ) { ll res=0; db dis; dis=BC.getDistance(oripot)+v1.y*tim; //第一种坐标系对应边BC,计算出起点高度+y轴经过距离Δy if( dis<0 ) res+=(ll)(-dis/h)+1; //如果方向为负方向,计算结果与直接整除略有不同 else res+=(ll)(dis/h); //正方向正常整除 dis=AC.getDistance(oripot)+v2.y*tim; //第一种坐标系对应边AC,计算出起点高度+y轴经过距离Δy if( dis<0 ) res+=(ll)(-dis/h)+1; else res+=(ll)(dis/h); dis=AB.getDistance(oripot)+v3.y*tim; //第一种坐标系对应边AB,计算出起点高度+y轴经过距离Δy if( dis<0 ) res+=(ll)(-dis/h)+1; else res+=(ll)(dis/h); return res>=k ; //最后判断当前的交点个数是否大于等于要求的个数 } void solve() { L=readb(),x=readb(),y=readb(),vx=readb(),vy=readb(),k=readb(); h=sqrt(3)*L/2.0; //三角形高度 v1=point(vx,vy); //第一种坐标系下的速度向量 v2=v1.Rotate(PI*2.0/3); //第二种坐标系下的速度向量(逆时针旋转120°) v3=v1.Rotate(-PI*2.0/3); //第三种坐标系下的速度向量(顺时针旋转120°) oripot=point(x,y); // 初始点位置 A=point(0,h); B=point(L/2.0,0); C=point(-L/2.0,0); AB=sLine(A,B); AC=sLine(A,C); BC=sLine(B,C); db l=0,r=1e10,mid; while( r-l>=1e-6 ) { mid=(l+r)/2.0; if( check(mid) ) r=mid; else l=mid; } printf("%lf\n",r); } int main() { int T=readb(); while( T-- ) solve(); return 0; }