hdu 5114 Collision (扩展欧几里得)

来源:互联网 发布:围棋文化内涵 知乎 编辑:程序博客网 时间:2024/06/03 19:04

Collision

Problem Description
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.
 

Input
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)
 

Output
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.

题目大意:有一个长宽分别为 x+1 y+1的矩形,左下角坐标为 0,0。现在有两个起点 坐标(x1,y1)(x2,y2) 他们移动速度都是(1,1),每秒横坐标向前一个单位,纵坐标向上一个单位,碰到边界会反弹。 问两个球会不会碰撞,如果能碰撞输出第一次碰撞的位置。


解题思路:

解决这类碰撞问题的常见套路都是将速度正交分解,分别考虑横坐标和纵坐标。

首先我们注意到一个问题是碰撞的点有可能在格中间,所以我们将题目中所有的数据都翻倍,也就是奇数节点代表的是以前的格中点。最后输出答案的时候记得÷2就可以了。

然后我们分析横坐标碰撞的情况,画图分析容易得到 (x1 + x2 +2t ) = 0 (mod 2x)

同理有 (y1 + y2 + 2t) = 0  ( mod 2y)

易得 t = k1 * x - (x1 + x2)/2

        t = k2 * y - (y1 + y2)/2

联立两个等式,我们可以发现可以应用扩展欧几里得求解。最后要保证时间 t 一定是正数即可。

注意 t 可以选择的周期是 lcm(x,y)


AC代码:

#include <bits/stdc++.h>using namespace std;#define LL long long#define ll long longll exgcd(ll a, ll b, ll &x, ll &y) // a*x + b*y = gcd(a,b){    if(b==0)    {        x = 1; y = 0;        return a;    }    ll d = exgcd(b,a%b,x,y);    ll temp = x;    x = y;    y = temp - a/b*y;    return d;}int main(){    int t;    scanf("%d", &t);    for(int cas = 1 ; cas <= t ; cas++){        LL x, y;        scanf("%I64d%I64d", &x, &y);        LL x1, y1, x2, y2;        scanf("%I64d%I64d%I64d%I64d", &x1, &y1, &x2, &y2);        LL k1, k2;        x1 *= 2, x2 *= 2, y1 *= 2, y2 *= 2, x *= 2, y *= 2;        LL d = exgcd(x, y, k1, k2);        printf("Case #%d:\n", cas);        double ansx, ansy;        ll t;        if(x1 == x2 && y1 == y2)    t = 0;        else if(x1 == x2)           t = (2 * y - y1 - y2) / 2;        else if(y1 == y2)           t = (2 * x - x1 - x2) / 2;        else if(((x1 + x2 - y1 - y2) / 2) % d != 0){            printf("Collision will not happen.\n");            continue;        }        else{            LL k = ((x1 + x2 - y1 - y2) / 2 / d);            t = k1 * x * k - (x1 + x2) / 2;            k = (x * y) / d;    //可选时间的周期            t = (t % k + k) % k;//需要把时间处理为非负数        }        ansx = (x1 + t) % (2 * x);        if(ansx >= x)    ansx = 2 * x - ansx;        ansy = (y1 + t) % (2 * y);        if(ansy >= y)    ansy = 2 * y - ansy;        printf("%.1f %.1f\n", ansx / 2.0, ansy / 2.0);    }    return 0;}



原创粉丝点击