zoukankan      html  css  js  c++  java
  • 欧几里得&扩展算法&扩展欧几里得

    欧几里得算法

    欧几里得算法又称为辗转相除法  用来计算gcd(a , b)

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

    时间复杂度:O(log(b))

    证明如下:

    gcd(a,b)=gcd(b,a mod b)
    证明:a可以表示成a = kb + r,则r = a mod b
    假设d是a,b的一个公约数,则有
    d|a, d|b,而r = a - kb,因此d|r
    因此d是(b,a mod b)的公约数
    假设d 是(b,a mod b)的公约数,则
    d | b , d |r ,但是a = kb +r
    因此d也是(a,b)的公约数
    因此(a,b)和(b,a mod b)的公约数是一样的,其最大公约数也必然相等,得证
    扩展算法
    算法描述:对于完全不为0的非负整数a , b。gcd(a , b)表示a , b的最大公约数,必然存在整数x , y,使得gcd(a , b) = a*x+b*y。
    证明如下:
    设 a>b。
    1,显然当 b=0,gcd(a,b)=a。此时 x=1,y=0;
    2,a>b>0 时
    设 ax1+ by1= gcd(a,b);
    bx2+ (a mod b)y2= gcd(b,a mod b);
    根据朴素的欧几里德原理有 gcd(a,b) = gcd(b,a mod b);
    则:ax1+ by1= bx2+ (a mod b)y2;
    即:ax1+ by1= bx2+ (a - [a / b] * b)y2=ay2+ bx2- [a / b] * by2;
    说明: a-[a/b]*b即为mod运算。[a/b]代表取小于a/b的最大整数。
    也就是ax1+ by1 == ay2+ b(x2- [a / b] *y2);
    根据恒等定理得:x1=y2; y1=x2- [a / b] *y2;
    这样我们就得到了求解 x1,y1 的方法:x1,y1 的值基于 x2,y2.
    上面的思想是以递归定义的,因为 gcd 不断的递归求解一定会有个时候 b=0,所以递归可以结束。
    算法实现:
    int kuo_zhan(int a , int b , int &x , int &y)
    {
        if(b == 0)
        {
            x = 1;
            y = 0;
            return a;
        }
        int q = gcd(b , a%b , y , x);
        y -= a/b*x;
        return q;
    }

    部分变换:

    变换之后实现如下:

    int kuoz_zhan_2(int a , int b , int &x , int &y)
    {
        if(b == 0)
        {
            x = 1;
            y = 0;
            return a;
        }
        int q = gcd(b , a%b , x , y);
        int tmp = x;
        x = y;
        y = tmp-a/b*y;
        return q;
    }

    证明如下:

    把这个实现和Gcd的递归实现相比,发现多了下面的x,y赋值过程,这就是扩展欧几里德算法的精髓。
    可以这样思考:
    对于a'=b,b'=a%b 而言,我们求得 x, y使得 a'x+b'y=Gcd(a',b')
    由于b'=a%b=a-a/b*b (注:这里的/是程序设计语言中的除法)
    那么可以得到:
    a'x+b'y=Gcd(a',b') ===>
    bx+(a - a / b * b)y = Gcd(a', b') = Gcd(a, b) ===>
    ay +b(x - a / b*y) = Gcd(a, b)
    因此对于a和b而言,他们的相对应的p,q分别是 y和(x-a/b*y)
    一般解:
    上面已经列出找一个整数解的方法,在找到p * a+q * b = Gcd(a, b)的一组解p0,q0后,p * a+q * b = Gcd(a, b)的其他整数解满足:
    p = p0 + b/Gcd(a, b) * t
    q = q0 - a/Gcd(a, b) * t(其中t为任意整数)
    扩展欧几里得
    算法描述:扩展欧几里得可以解决不定方程求解问题,如a*x+b*y=c,其中c=gcd(a , b)时为扩展问题,c不为gcd(a , b)时,需要满足c%gcd(a , b)=0才会有解,否则无解
    证明略。
    至于pa+qb=c的整数解,只需将p * a+q * b = Gcd(a, b)的每个解乘上 c/Gcd(a, b) 即可,但是所得解并不是该方程的所有解,找其所有解的方法如下:
    在找到p * a+q * b = Gcd(a, b)的一组解p0,q0后,可以
    得到p * a+q * b = c的一组解p1 = p0*(c/Gcd(a,b)),q1 = q0*(c/Gcd(a,b)),p * a+q * b = c的其他整数解满足:
    p = p1 + b/Gcd(a, b) * t
    q = q1 - a/Gcd(a, b) * t(其中t为任意整数)
    p 、q就是p * a+q * b = c的所有整数解。
  • 相关阅读:
    因host命令导致无法正常SHUTDOWN的实验
    ORACLE SEQUENCE 介绍
    SQL Server数据库附加失败:错误5120和错误950
    Java中怎样由枚举常量的ordinal值获得枚举常量对象
    后会终无期,且行且珍惜
    Objective-C辛格尔顿
    自己动手写一个编译器Tiny语言解析器实现
    linux于test 订购具体解释
    Linux高性能server规划——处理池和线程池
    《采访中收集程序猿》学习记录8
  • 原文地址:https://www.cnblogs.com/Flower-Z/p/9340342.html
Copyright © 2011-2022 走看看