• [POJ 1061]--青蛙的约会(扩展欧几里得)


                                                                   青蛙的约会

    Time Limit: 1000MS
    Memory Limit: 10000K

     


    题目链接:http://poj.org/problem?id=1061

    Description

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

    Input

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

    Output

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

    Sample Input

    1 2 3 4 5

    Sample Output

    4

     

    解题思路:首先把这道题转化为相关的数学方程:(n-m)t+pL=x-y,即二元一次不定方程at+bp=c,根据数论的相关定理,得知当c%gcd(a,b)==0时方程有整数解,

         否则没有,即此题无解。

    引用以下定理:

    定理1 gcd(a,b)是ax+by的线性组合的最小正整数,x,y∈z;
    定理2 如果ax+by=c,x,y∈z;则c%gcd==0;
    定理3 如果a,b是互质的正整数,c是整数,且方程ax+by=c

    (1)有一组整数解x0,y0则此方程的一切整数解可以表示为x=x0+bt;y=y0-at;t∈z;

    (2)方程at+bp=c左右两边同除以gcd(a,b),得a1t+b1p=c1,再解最小正整数线性组合得一组解x1,y1,

        则所求方程的一组解为T=x1*c1,P=y1*c1,根据(2)式可得t的最小正整数解为(T%b1+b1)%b1,此即为可行时所求解,

    注意:因为所给数据比较大,这里全部用__int64。

    代码如下:

     1 #include <iostream>
     2 using namespace std;
     3 
     4 __int64 t, p;
     5 __int64 get_gcd(__int64 a, __int64 b){
     6     return !b?a:get_gcd(b, a%b);
     7 }
     8 
     9 void extended_gcd(__int64 a, __int64 b){
    10     if (!b){
    11         t = 1;
    12         p = 0;
    13     }
    14     else{
    15         __int64 temp;
    16         extended_gcd(b, a%b);
    17         temp = t - a / b*p;
    18         t = p;
    19         p = temp;
    20     }
    21 }
    22 
    23 int main(){
    24     __int64 x, y, n, m, L, gcd;
    25     cin >> x >> y >> m >> n >> L;
    26     if (m == n){
    27         cout << "Impossible" << endl;
    28         return 0;
    29     }
    30     __int64 a, b, c, c1;
    31     a = n - m;
    32     b = L;
    33     c = x - y;
    34     gcd = get_gcd(a, b);
    35     c1 = c%gcd;
    36     if (c1 != 0){
    37         cout << "Impossible" << endl;
    38         return 0;
    39     }
    40     c /= gcd;
    41     a /= gcd;
    42     b /= gcd;
    43     extended_gcd(a, b);
    44     t *= c;
    45     p *= c;
    46     t = (t%b + b) % b;
    47     cout << t << endl;
    48     return 0;
    49 }
    View Code

    当然也可以这么写:

    d为n-m和L的最大公约数,x为(n-m)/d对L/d的逆元,即((n-m)/d) * x ≡ 1(mod L/d),即((n-m)/d) * x + (L / d)* y = 1的一组解,

    所以((m-m)/d) * x + (L / d)* y = (x-y)/d的一组解为x0 = (x-y)/d * x.这也是(n - m) * x+ L * y = (x - y)的一组解。 (代码中cycle代表d)。

     1 #include<iostream>
     2 using namespace std;
     3 long gcd(long a, long b){
     4     return !b ? a : gcd(b, a%b);
     5 }
     6 int main(){
     7     long x, y, m, n, L, i, cycle;
     8     while (cin >> x >> y >> m >> n >> L){
     9         if (m > n) cycle = (y - x + L) % L;
    10         else{
    11             cycle = (x - y + L) % L;
    12             swap(m, n);
    13         }
    14         if (n == m || cycle%gcd(L, m - n)){
    15             cout << "Impossible" << endl;
    16             continue;
    17         }
    18         for (i = 0;; i++){
    19             if ((i*L + cycle) % (m - n) == 0){
    20                 cout << (i*L + cycle) / (m - n) << endl;
    21                 break;
    22             }
    23         }
    24     }
    25     return 0;
    26 }
    View Code
  • 相关阅读:
    DAY-4 Linux基础及常用命令(1)
    DAY-3 计算机基础之网络
    DAY-2 计算机基础之操作系统
    DAY-1 计算机基础
    梅花作品欣赏
    简洁大气网址(国外)跟设计大学的案例很像
    animate css3 应用的借鉴,一个同事写的JS
    漂亮的素材
    几个不错的素材站
    正式开始我的技术生涯
  • 原文地址:https://www.cnblogs.com/zyxStar/p/4580516.html
Copyright © 2020-2023  润新知