题目链接:HDU-5114
题意为给一个矩形n*m,两个给定坐标的球在矩形中都以(1,1)的速度运动,碰到边界会反弹,求第一次碰撞的坐标。
思路是首先把运动分解为横向运动和纵向运动分别考虑,则变成两个追赶运动。假设(x_2>x_1,y_2>y_1),可以得到x坐标相同的时间为(t_x=n - frac{x_2-x_1}{2}-x_1+kn = n - frac{x_1+x_2}{2}+kn ),y坐标相同时间为(t_y=m - frac{y_2-y_1}{2}-y_1+k'm = m - frac{y_1+y_2}{2}+k'm ),其中 k,k' >= 0。
于是我们就可以得到(t= m - frac{y_1+y_2}{2}+k'm =n - frac{x_1+x_2}{2}+kn),变换就是我们熟悉的(kn - k'm = (m - frac{y_1+y_2}{2})-(n - frac{x_1+x_2}{2})),也就是二元一次方程求最小非负整数解。
但是这里面还有一个问题,就是方程中由于有(frac{y_1+y_2}{2})和(frac{x_1+x_2}{2}),存在小数。所以我们把所有值全部提前*2,这里可以理解为所有坐标和矩形尺寸全部拉伸为原来的两倍。
于是方程变成了(2nk - 2mk' = (2m - y_1 - y_2)-(n - x_1 - x_2)),求解即可。
题目中还有一些需要注意的细节,比如((x_1=x_2 ,y_1=y_2)),((x_1=x_2 ,y_1!=y_2)),((x_1!=x_2 ,y_1=y_2))三种情况,并不满足上述方程,需要特判。
代码如下:
1 #include<cstdio> 2 #include<set> 3 #include<map> 4 #include<cstring> 5 #include<algorithm> 6 #include<queue> 7 #include<iostream> 8 using namespace std; 9 typedef long long LL; 10 11 12 //拓展欧几里得算法 13 //求ax+by=gcd(a,b)的一组解 14 //其他解为x=x0+kb',y=y0-ka' 15 //a'=a/gcd(a,b),b'=b/gcd(a,b) 16 LL extgcd(LL a,LL b,LL &x,LL &y) 17 { 18 LL d=a; 19 if(b!=0) 20 { 21 d=extgcd(b,a%b,y,x); 22 y-=(a/b)*x; 23 } 24 else { x=1; y=0; } 25 return d; 26 } 27 28 //求最大公约数 29 LL gcd(LL a,LL b) 30 { 31 if(b==0) return a; 32 return gcd(b,a%b); 33 } 34 35 36 int main() 37 { 38 #ifdef LOCAL 39 freopen("in.txt","r",stdin); 40 #endif 41 LL t; 42 scanf("%lld",&t); 43 for(LL tt=1;tt<=t;tt++) 44 { 45 printf("Case #%lld: ",tt); 46 LL n,m,x1,x2,y1,y2; 47 scanf("%lld%lld%lld%lld%lld%lld",&n,&m,&x1,&y1,&x2,&y2); 48 LL t2; 49 LL tx2=(2*n-x1-x2),ty2=(2*m-y1-y2); 50 if(x1==x2 && y1==y2) {printf("%.1lf %.1lf ",1.0*x1,1.0*y1); continue;} 51 else if(x1==x2) t2=ty2; 52 else if(y1==y2) t2=tx2; 53 else 54 { 55 LL k,kk; 56 LL g=extgcd(2*n,2*m,k,kk); 57 LL tmp=ty2-tx2; 58 if(tmp%g) 59 { 60 printf("Collision will not happen. "); 61 continue; 62 } 63 else 64 { 65 k=tmp/g*k; 66 LL mm=2*m/g; 67 k=(k % mm + mm) % mm; 68 t2=tx2+k*2*n; 69 if(t2<ty2) t2+=(ty2-t2)/k*k; 70 if(t2<ty2) t2+=k; 71 } 72 } 73 LL xx=(2*x1+t2)%(2*n); 74 LL yy=(2*y1+t2)%(2*m); 75 if(((2*x1+t2)/(2*n))%2) xx=2*n-xx; 76 if(((2*y1+t2)/(2*m))%2) yy=2*m-yy; 77 printf("%.1lf %.1lf ",xx/2.0,yy/2.0); 78 } 79 return 0; 80 }