zoukankan      html  css  js  c++  java
  • 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 即可。

     

  • 相关阅读:
    读取Config文件工具类 PropertiesConfig.java
    MD5编码工具类 MD5Code.java
    文件上传工具类 UploadUtil.java
    删除文件夹工具类 DeleteFolder.java
    目录处理工具类 DealWithDir.java
    文件/目录部分处理工具类 DealDir.java
    目录操作工具类 CopyDir.java
    功能更强大的格式化工具类 FormatUtils.java
    日期转换工具类 CommUtil.java
    MVC学习笔记1-MVC家族间的区别
  • 原文地址:https://www.cnblogs.com/dengeven/p/3418920.html
Copyright © 2011-2022 走看看