您的位置:首页 > 其它

HDU 5514 Collision(扩展欧几里得+解方程)——2014ACM/ICPC亚洲区北京站

2017-06-26 18:45 399 查看
传送门

Matt is playing a naive computer game with his deeply loved pure girl.

The playground is a rectangle with walls around. Two balls are put in different positions inside the rectangle. The balls are so tiny that their volume can be ignored. Initially, two balls will move with velocity (1, 1). When a ball collides with any side of the rectangle, it will rebound without loss of energy. The rebound follows the law of refiection (i.e. the angle at which the ball is incident on the wall equals the angle at which it is reflected).

After they choose the initial position, Matt wants you to tell him where will the two balls collide for the first time.
[align=left]Input[/align] The first line contains only one integer T which indicates the number of test cases.

For each test case, the first line contains two integers x and y. The four vertices of the rectangle are (0, 0), (x, 0), (0, y) and (x, y). (1 ≤ x, y ≤ 105)

The next line contains four integers x1, y1, x2, y2. The initial position of the two balls is (x1, y1) and (x2, y2). (0 ≤ x1, x2 ≤ x; 0 ≤ y1, y2 ≤ y)
[align=left]Output[/align] For each test case, output “Case #x:” in the first line, where x is the case number (starting from 1).

In the second line, output “Collision will not happen.” (without quotes) if the collision will never happen. Otherwise, output two real numbers xc and yc, rounded to one decimal place, which indicate the position where the two balls will first collide.
[align=left]Sample Input[/align]
3

10 10

1 1 9 9

10 10

0 5 5 10

10 10

1 0 1 10

[align=left]Sample Output[/align]
Case #1:

6.0 6.0

Case #2:

Collision will not happen.

Case #3:

6.0 5.0


HintIn first example, two balls move from (1, 1) and (9, 9) both with velocity (1, 1), the ball starts from (9, 9) will rebound at point (10, 10) then move with velocity (−1, −1). The two balls will meet each other at (6, 6).

题目大意:

给了一个 x∗y 的矩阵,在这个矩阵中有两个小球(体积可以忽略):小球1 (x1,y1), 小球2 (x2,y2) 现在这两个小球都以 (1,1) 的速度在运动,如果碰到边界会发生反弹(不损失能量),现在求两个小球第一次碰撞时的坐标。

解题思路:

我们可以将这个小球的运动在 x 轴 和 y 轴上进行分解,在 x 轴上是匀速直线运动,同理在 y 轴上也是匀速直线运动。现在小球1 和 小球2 的坐标有四种情况:

1)x1=x2 and y1=y2

2)x1=x2 and y1≠y2

3)x1≠x2 and y1=y2

4)x1≠x2 and x1≠y2

现在就四种情况分别进行讨论:

如果是第一种情况的话,第一次碰撞的点就是 (x1,y1) || (x2,y2)

如果是第二种情况的话,我们首先设在第一次碰撞的时间为 ty,第一次碰撞的点为 (xp,yp)

那么就有 下图所示方程成立:



更正:对于图中的第二个式子有错误,应该是: ty=yp−y1

然后可以解得: ty = (2∗y−(y1+y2))2,然后 (xp,yp) 就能确定了

同理,如果是第三种情况的话,我们可以解出 tx = (2∗x−(x1+x2))2, 然后 (xp,yp) 也能确定了

如果是第四种情况的话就只需要加上一个周期就行了,对于 x 轴来说,

tx = (2∗x−(x1+x2))2+a∗x a:表示经过a个周期,周期为 x

ty = (2∗y−(y1+y2))2+b∗y b:表示经过b个周期,周期为 y

然后又因为 tx = ty, 然后联力两个方程组得到如下方程:

(2∗x−(x1+x2))2+a∗x=(2∗y−(y1+y2))2+b∗y

移项得:

a∗x−b∗y=(2∗y−(y1+y2))2−(2∗x−(x1+x2))2

这就是我们所常见的一元二次方程,然后扩展欧几里得一下求得 a 的最小正整数解就 OK 了。

需要注意的是,这里有一个小 trick:因为方程里有除法操作,所以我们先把所有的变量乘以 2,然后在操作就行了,还有就是 如果最后求得的解如果大于 x 或者 y 的话,就是反弹了,然后减一下就行,具体看代码。

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
inline LL GCD(LL a, LL b){
if(b == 0) return a;
return GCD(b, a%b);
}
void Exgcd(LL a, LL b, LL &x, LL &y){
if(b == 0){
x = 1, y = 0;
return;
}
LL x1, y1;
Exgcd(b, a%b, x1, y1);
x = y1;
y = x1 - (a/b)*y1;
}
int main()
{
int T; scanf("%d", &T);
for(int cas=1; cas<=T; cas++){
LL x, y, x1, x2, y1, y2;
scanf("%lld%lld%lld%lld%lld%lld", &x, &y, &x1, &y1, &x2, &y2);
x<<=1, y<<=1, x1<<=1, y1<<=1, x2<<=1, y2<<=1;
printf("Case #%d:\n",cas);
LL tx = (2*x-(x1+x2))/2, ty = (2*y-(y1+y2))/2;
if(x1==x2 && y1==y2) printf("%.1f %.1f\n", 0.5*x1, 0.5*y1);
else if(x1 == x2){
if(y1 > y2) swap(y1, y2);
x1 = (x1+ty)%(2*x), y1 = (y1+ty)%(y*2);
if(x1 > x) x1 = 2*x - x1;
if(y1 > y) y1 = 2*y - y1;
printf("%.1f %.1f\n", 0.5*x1, 0.5*y1);
}
else if(y1 == y2){
if(x1 > x2) swap(x1, x2);
x1 = (x1+tx)%(2*x), y1 = (y1+tx)%(y*2);
if(x1 > x) x1 = 2*x - x1;
if(y1 > y) y1 = 2*y - y1;
printf("%.1f %.1f\n", 0.5*x1, 0.5*y1);
}
else{
LL tp = ty - tx;
LL d = GCD(x, y);
if(tp % d) puts("Collision will not happen.");
else{
LL a = x / d, b = y / d, c = tp / d, xx;
Exgcd(a, b, xx, ty);
xx *= c;
xx = (xx%b+b)%b;
tx = tx + x*xx;
x1 = (x1+tx)%(2*x), y1 = (y1+tx)%(y*2);
if(x1 > x) x1 = 2*x - x1;
if(y1 > y) y1 = 2*y - y1;
printf("%.1f %.1f\n", 0.5*x1, 0.5*y1);
}
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: