POJ1061 青蛙的约会

题目来源:http://poj.org/problem?id=1061

题目大意:

  两只青蛙在网上相识了,它们聊得很开心,于是觉得很有必要见一面。它们很高兴地发现它们住在同一条纬度线上,于是它们约定各自朝西跳,直到碰面为止。可是它们出发之前忘记了一件很重要的事情,既没有问清楚对方的特征,也没有约定见面的具体位置。不过青蛙们都是很乐观的,它们觉得只要一直朝着某个方向跳下去,总能碰到对方的。但是除非这两只青蛙在同一时间跳到同一点上,不然是永远都不可能碰面的。为了帮助这两只乐观的青蛙,你被要求写一个程序来判断这两只青蛙是否能够碰面,会在什么时候碰面。 
我们把这两只青蛙分别叫做青蛙A和青蛙B,并且规定纬度线上东经0度处为原点,由东往西为正方向,单位长度1米,这样我们就得到了一条首尾相接的数轴。设青蛙A的出发点坐标是x,青蛙B的出发点坐标是y。青蛙A一次能跳m米,青蛙B一次能跳n米,两只青蛙跳一次所花费的时间相同。纬度线总长L米。现在要你求出它们跳了几次以后才会碰面。 

输入:输入只包括一行5个整数x,y,m,n,L,其中x≠y < 2000000000,0 < m、n < 2000000000,0 < L < 2100000000。

输出:输出碰面所需要的跳跃次数,如果永远不可能碰面则输出一行"Impossible"


Sample Input

1 2 3 4 5

Sample Output

4

终于有一道中文题目了,真是泪流满面T^T..

  由题意知,实际上问题是要求解下面的方程:  

      (1)

  其中 t 为未知数,要求的是 t 的非负最小值。上式可变形为: (2)

  其中 t 和 k 为未知数。再将上式简化为(3) 的形式。其中, a b c 均为整数常数。数论中的相关理论(具体什么理论我也不知道=。=)保证了:当 c = gcd(a, b)时,该方程的 t 和 k 一定有解。所以如果可以把(2)式转化为 (4) 的形式,则原问题有解,否则无解,应输出“Impossible.”。

  接下来说明(4)式的解法--扩展的欧几里得算法

  首先请移步这里回顾一下求两数最大公约数的朴素欧几里得算法。然后, 我们把代码搬过来:

int gcd(int a, int b) {
    if(b == 0)
        return a;
    return gcd(b, a % b);
}

  所谓的扩展欧几里得算法,代码如下:

int x, y;

int
ex_gcd(int a, int b) { if (b == 0) { x = 1; y = 0; return a; } else { int r = ex_gcd(b, a % b); int t = x; x = y; y = t - a / b * y; return r; } }

这里的a, b与前面方程(4)里的a, b对应, x, y对应t, k,返回值为gcd(a, b)。[ax + by = gcd(a, b)]. 我们发现,ex_gcd算法与gcd相比,多了 x 与 y 的赋值过程。只要在纸上演算一下,会发现其实算法很好理解:

1. b == 0 时,对应方程 gcd(a, b) = a, 对应的原方程为:ax + 0y = a, 所以可以赋值 x = 1, y = 0;

2. 当 b != 0 时,因为gcd(a, b) = gcd(b, a % b). 所以存在x'和y'满足:

  ax + by = gcd(a, b)

       = gcd(b, a % b)

       = bx' + (a % b)y'

       = bx' + (a - a / b * b)y'

       = ay' + b(x' - a / b * y')

于是我们从上面连等式中可以找到对应关系:x = y'; y = x' - a / b * y'. 算法就是利用该递推关系就求出方程(4)的一组解,设之为(x0, y0)。

显然解不是唯一的,而是应该构成一组解系。设gcd(a, b) = d, 则 ax0 + by0 = d, 且有:

  

于是我们构造出了解系: 其中n为任意整数。

然后对于一般形式的方程 ax + by = c, 则对应着解系. 所以如果 c/gcd(a, b) 是整数,则该方程有整数解,若不是则无整数解。

那么回到题目中,本题实际上求的是满足方程的x中的最小非负值,求得了x0和d后应该是不难得到了。至此应该把原理讲清楚了吧,嗯,上AC代码。            

 1 ////////////////////////////////////////////////////////////////
 2 //        POJ1061 Frogs' Dating
 3 //        Memory: 216K        Time: 0MS
 4 //        Language: C++        Result : Accepted
 5 ////////////////////////////////////////////////////////////////
 6 
 7 #include <iostream>
 8 
 9 using namespace std;
10 
11 long long x, y;
12 
13 long long ex_gcd(long long a, long long b) {
14     if (b == 0) {
15         x = 1;
16         y = 0;
17         return a;
18     } else {
19         long long r = ex_gcd(b, a % b);
20         long long t = x;
21         x = y;
22         y = t - a / b * y;
23         return r;
24     }
25 }
26 
27 int main(void) {
28     long long X, Y, m, n, L, c, d, t;
29     cin >> X >> Y >> m >> n >> L;
30     c = X - Y;
31     d = ex_gcd(n - m, L);
32     t = c % d;
33     if (t == 0) {
34         long long k = c / d;
35         x *= k;
36         t = d * x / L;
37         x -= t * L / d;
38         if (x < 0) {
39             x += L / d;
40         }
41         cout << x << endl;
42     } else {
43         cout << "Impossible" << endl;
44     }
45     return 0;
46 }
View Code

关于求满足条件的最小非负数的附加解释:

  令 ,此时求得的n对应着最接近0的x,如果算出的x小于0,则在它的基础上再加一个周期 b/d 即可。

 

posted @ 2013-11-12 19:11  小菜刷题史  阅读(312)  评论(0编辑  收藏  举报