zoukankan      html  css  js  c++  java
  • poj 1061 (扩展欧几里德算法)


    首先先抛出一个例题:


                                                                                                        青蛙的约会
    Time Limit: 1000MS   Memory Limit: 10000K
    Total Submissions: 89761   Accepted: 16131

    Description

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

    Input

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

    Output

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

    Sample Input

    1 2 3 4 5

    Sample Output

    4


    涉及知识点:ext_gcd

    代码如下:

    #include<stdio.h>
    #include<math.h>
    #define LL long long
    
    LL extend_gcd(LL a, LL b, LL &x, LL &y)
    {
        if(b==0)
        {
            x = 1;
            y = 0;
            return a;
        }
        LL d = extend_gcd(b, a%b, x, y);
        LL t = x;
        x = y;
        y = t-a/b*y;
        return d;
    }
    
    int main()
    {
        LL x, y, n, m, L;
        LL a,b,c,d;
    
        while(~scanf("%lld%lld%lld%lld%lld", &x, &y, &m, &n, &L))
        {
            LL p,q;
            a=n-m, b=L, c = x-y;
            d = extend_gcd(a, b, p, q);
    
            if(c%d!=0) printf("Impossible
    ");
            else
            {
                p = p*(c/d);
                p = (p%b + b)%b;
                printf("%lld
    ", p);
            }
        }
        return 0;
    
    

    注意:

    ext_gcd模板求得的只是 当 ax + by = gcd(a,b)时,x 和 y 的值。 但是当ax ' + b y' = c 如果有解,则应满足以下情况:,c能够整除gcd(a, b),也就是c = k  *(gcd(a, b)) 其中k为整数。那么此时的 x' 就等于kx, y' 就等于 ky,即 x' = kx,    y = ky',对应文中代码部分为: p = p*(c/d);。如果想求最小正整数解的话,就要加上 p = (p%b + b)%b 了。

    —————————————————————————————————————————————————————————————————————————————

              今天看了一下gcd算法,本来学的教材上有这个,但不知道还叫欧几里德算法,于是又重新看了一边,搜的时候没想到还有新的收获,又看到了拓展欧几里德算法。

      先说一下gcd吧,也叫辗转相除法。给定两个数 a,b , 求两个数中的最大公约数。

     int gcd(int n, int m) // n>m
    {
      if(n%m == 0)
             return m;
     else
            return (m, n%m);

    }

    思路比较简单,两个数(a, b,其中a>b)的最大公约数就等于其中较小数(b)和(a%b)这两个数的最大公约数。

    最小公倍数等于 两个数的乘积除以两个数的最大公约数。

    —————————————————————————————————————————————————————————————————————————————

    再说一下extend_gcd( 拓展欧几里得算法),ext_gcd 算法由裴蜀定理中得出:

              知识点:  在数论中,裴蜀等式裴蜀定理是一个关于最大公约数(或最大公约式)的定理。裴蜀定理得名于法国数学家艾蒂安·裴蜀,说明了对任何整数ab和它们的最大公约数d,关于未知数xy线性丢番图方程(称为裴蜀等式):

    ax+by=m

    有整数解时当且仅当md倍数。裴蜀等式有解时必然有无穷多个整数解,每组解xy都称为裴蜀数,可用扩展欧几里得算法求得。

    例如,12和42的最大公约数是6,则方程12x+42y=6有解。事实上有(-3)×12 + 1×42 = 6及4×12 + (-1)×42 = 6。

    特别来说,方程 ax+by=1 有整数解当且仅当整数ab互素

    裴蜀等式也可以用来给最大公约数定义:d其实就是最小的可以写成ax+by形式的正整数。这个定义的本质是整环中“理想”的概念。因此对于多项式整环也有相应的裴蜀定理。

     

                历史历史上首先证明关于整数的裴蜀定理的并不是裴蜀,而是17世纪初的法国数学家克劳德-加斯帕·巴歇·德·梅齐里亚克Claude-Gaspard Bachet de Méziriac)。他在于1624年发表的著作《有关整数的令人快乐与惬意的问题集》(Problèmes plaisans et délectables qui se font par les nombres)第二版中给出了问题的描述和证明[1]

    然而,裴蜀推广了梅齐里亚克的结论,特别是探讨了多项式中的裴蜀等式,并给出了相应的定理和证明[2]


            证明过程如下:

         整数中的裴蜀定理

             对任意两个整数ab,设d是它们的最大公约数。那么关于未知数xy线性丢番图方程(称为裴蜀等式):

          displaystyle ax+by=m

    有整数解(x,y) 当且仅当md倍数。裴蜀等式有解时必然有无穷多个解。

    证明

    如果 ab 中有一个是0,比如a=0,那么它们两个的最大公约数是b。这时裴蜀等式变成displaystyle by=m,它有整数解(x,y) 当且仅当md 的倍数,而且有解时必然有无穷多个解,因为x 可以是任何整数。定理成立。

    以下设 ab 都不为0。

    A = {xa+yb; (x;y) in ^2},下面证明A中的最小正元素是ab 的最大公约数。

    首先,A cap N^* 不是空集(至少包含|a||b|),因此由于自然数集合是良序的,A 中存在最小正元素d_0 = x_0a + y_0b。考虑A中任意一个正元素p=x_1a + y_1b)对d_0带余除法:设p=qd_0+r,其中q 为正整数,0 le r < d_0。但是

    r = p-qd_0 =x_1a + y_1b - q ( x_0a + y_0b) in A

    因此 r=0d_0  |  p。也就是说,A中任意一个正元素p都是d_0 的倍数,特别地:d_0  |  ad_0  |  b。因此d_0ab公约数

    另一方面,对 ab 的任意正公约数d,设a=kdb=ld,那么

    d_0 =x_0a + y_0b = ( x_0k + y_0l )d

    因此 d  |  d_0。所以d_0ab最大公约数

    在方程ax+by=m中,如果 m= m_0 d_0,那么方程显然有无穷多个解:

    left{left( m_0 left(x_0+frac{kb}{d}
ight), m_0 left( y_0-frac{ka}{d}
ight) 
ight) mid k in mathbb{Z} 
ight}

    相反的,如果ax+by=m有整数解,那么|m| in A,于是由前可知d_0  |  |m|(即d_0  |  m)。

    m=1时,方程有解当且仅当ab互质。方程有解时,解的集合是

     left{left( frac{m}{d} left(x_0+frac{kb}{d}
ight), frac{m}{d} left( y_0-frac{ka}{d}
ight) 
ight) mid k in mathbb{Z} 
ight} 。其中(x_0,y_0)是方程ax+by=d的一个解,可由辗转相除法得到。

    所有解中,有且仅有一个解(x,y) 满足-b le x le b-a le y le a


    拓展欧几里德算法:见链接  http://zh.wikipedia.org/wiki/%E6%89%A9%E5%B1%95%E6%AC%A7%E5%87%A0%E9%87%8C%E5%BE%97%E7%AE%97%E6%B3%95

    每天训练发现我比别人做的好慢,但是理解的更深刻,如果一开始学一个新知识点就搜模板,那么这样的人是走不远的,毕业之后带走的只有思维,什么荣誉,奖杯都已经不重要了。
  • 相关阅读:
    108. Convert Sorted Array to Binary Search Tree
    107. Binary Tree Level Order Traversal II
    106. Construct Binary Tree from Inorder and Postorder Traversal
    105. Construct Binary Tree from Preorder and Inorder Traversal
    104. Maximum Depth of Binary Tree
    103. Binary Tree Zigzag Level Order Traversal
    102. Binary Tree Level Order Traversal
    系统和进程相关信息
    文件I/0缓冲
    系统编程概念(文件系统mount等函数的使用)
  • 原文地址:https://www.cnblogs.com/6bing/p/3931241.html
Copyright © 2011-2022 走看看