HDU多校3 - 6798 Triangle Collision(几何+旋转坐标系)
題目鏈接:點擊查看
題目大意:給出一個等邊三角形的區域,再給出初始時一個質點的位置 ( x , y?) 和初始速度 ( vx , vy ) ,現在質點會不斷運動,當碰到三角形的內壁時會根據角度反彈,問小球第 k 次碰到三角形的內壁的時間
題目分析:k 非常大,肯定不能暴力去模擬每一次小球的運動,借用題解的一句話更好理解:
靈感來自用激光筆往鏡子中射入激光被多次反射。
人眼從激光筆的視角來看,光束并沒有被 “反射”,而是穿入了 “鏡子中的世界”。
將二維平面視為無窮大,大概就是這樣互相拼接而成的等邊三角形假設點 A 為起點,點 B 為一段時間后到達的位置,則線段 AB 穿過的三角形的邊數,就是質點碰撞三角形內壁的次數了
這樣一來,可以二分時間,然后去檢查線段穿過的次數與題目中給出 k 的關系,當然,計算穿過的邊數也是有技巧的,如果硬算投影的話應該也是可以的,只是比較麻煩,首先考慮如果只是計算穿過的藍色線段的數量,可以直接根據 y 的值稍加計算得到,同理,可以旋轉一下坐標系,這樣就能很方便的求出穿過黃色和紅色直線的條數了
借用一下大佬博客的圖片:https://blog.csdn.net/jk_chen_acmer/article/details/107641065
像上面一樣,每次逆時針旋轉 120 度即可
注意一下,因為我們在旋轉后,想要使得初始的三角形的三條邊位于 x 軸上,所以初始點 P 是圍繞著三角形的中心旋轉的,而速度向量是 V - O 構成的,換句話說,需要將點 V 和點 O 分別旋轉后再做減法得到向量(這樣操做或許比較麻煩,但個人看來是最容易理解的)
因為在進行上述旋轉后,有一個好處就是,初始時的點 P 的 y 坐標一定是大于 0 的,所以此時對于運動停止時的點 Q ,我們分兩種情況討論:
代碼:
#include<iostream> #include<cstdio> #include<string> #include<ctime> #include<cmath> #include<cstring> #include<algorithm> #include<stack> #include<climits> #include<queue> #include<map> #include<set> #include<sstream> #include<cassert> #include<bitset> using namespace std;typedef long long LL;typedef unsigned long long ull;const int inf=0x3f3f3f3f;const int N=2e5+100;const double eps = 1e-8;const double pi = acos(-1.0);int sgn(double x){if(fabs(x) < eps)return 0;if(x < 0)return -1;else return 1; }struct Point{double x,y;Point(){}Point(double _x,double _y){x = _x;y = _y;}bool operator == (Point b)const{return sgn(y-b.y) == 0;}bool operator < (Point b)const{return sgn(y-b.y)<0;}Point operator -(const Point &b)const{return Point(x-b.x,y-b.y);}Point operator +(const Point &b)const{return Point(x+b.x,y+b.y);}Point operator *(const double &k)const{return Point(x*k,y*k);}//叉積double operator ^(const Point &b)const{return x*b.y - y*b.x;}//點積double operator *(const Point &b)const{return x*b.x + y*b.y;}//返回兩點的距離double distance(Point p){return hypot(x-p.x,y-p.y);}//`繞著p點逆時針旋轉angle`Point rotate(Point p,double angle){Point v = (*this) - p;double c = cos(angle), s = sin(angle);return Point(p.x + v.x*c - v.y*s,p.y + v.x*s + v.y*c);} };double L,x,y,vx,vy,h;int k;Point P[4],Q[4],V[4],O[4],T;LL cal(double t,int i) {Point Q=P[i]+V[i]*t;if(sgn(Q.y)>=0)return (LL)floor(Q.y/h);elsereturn 1LL-(LL)ceil(Q.y/h); }int main() { #ifndef ONLINE_JUDGE // freopen("data.in.txt","r",stdin); // freopen("data.out.txt","w",stdout); #endif // ios::sync_with_stdio(false);int w;cin>>w;while(w--){scanf("%lf%lf%lf%lf%lf%d",&L,&x,&y,&vx,&vy,&k);h=sqrt(3)*L/2.0;T=Point(0,h/3.0);//中心點O[1]=Point(0,0),O[2]=O[1].rotate(T,pi*2.0/3.0),O[3]=O[1].rotate(T,pi*4.0/3.0);//原點P[1]=Point(x,y),P[2]=P[1].rotate(T,pi*2.0/3.0),P[3]=P[1].rotate(T,pi*4.0/3.0);//初始點V[1]=Point(vx,vy),V[2]=V[1].rotate(T,pi*2.0/3.0),V[3]=V[1].rotate(T,pi*4.0/3.0);//速度向量for(int i=1;i<=3;i++)V[i]=V[i]-O[i];//得到速度向量double l=0,r=1e10,ans;while(fabs(l-r)>=1e-5){double mid=(l+r)*0.5;if(cal(mid,1)+cal(mid,2)+cal(mid,3)>=k){ans=mid;r=mid;}elsel=mid;}printf("%.10f\n",ans);}return 0; }?
總結
以上是生活随笔為你收集整理的HDU多校3 - 6798 Triangle Collision(几何+旋转坐标系)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: HDU多校3 - 6797 Tokits
- 下一篇: HDU多校4 - 6808 Go Run