欧几里得算法与扩展欧几里得算法

欧几里得算法, 是用来求两数之前的最大公约数的一个算法, 又称辗转相除法.

记: gcd(a,b)为a,b两数的最大公约数

那么有   gcd(a,b)  ==  gcd(b,a%b)

具体证明如下 :

令 a%b = r

那么总会存在一个k使得  a = b*k+r

所以   r = a - b*k;

设 x 为a,b的公约数, 那么 a%x==0&&b%x==0

所以r % x == 0 又因为a%b == r  所以方程式可以改为   (a%b) % x  == 0;

所以x又是a%b和b的共同的公约数,

因为x事先没有确定, 所以x可以取任意a与b的公约数,

既然a与b的公约数 和 b与a%b的公约数都相同,

那么 也就是说明 a和b的最大公约数 与 b和a%b的最大公约数相同

因此   gcd( x,y ) == gcd(y,x%y).

以上是欧几里得算法的证明, 代码为:

int gcd(int x,int y){
    if(y == 0) return x;
    return gcd(y,x%y);
}

有一个定理为 对于任意整数a,b都有 ax+by = gcd(a,b)

我们知道欧几里得算法是可以求出gcd(a,b)的, 但是x,y怎么求呢,

对于任意整数a 和 b 我们有 ax + by = gcd(a,b);

又根据之前的结论知道    gcd(b,a%b) == gcd(a,b).

所以上面方程式可以改为   b * x'  +  (a%b)* y' = gcd(a,b);

又因为 a%b可以改写为 a - (a/b)*b         //   a/b向零取整

所以原式可以改写为    b* x' + a* y'- (a/b)*b* y' = gcd(a,b).

此时方程又可以改写成   a* y'  + b * ( x' - (a/b)* y') = gcd(a,b).

将上面的式子拿下来进行比较发现

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

a * x + b* y = gcd(a,b)

发现两式子的a,b都重合了, 综上发现一个x和y的值

即   x = y' ,     y = ( x' - (a/b)* y' ).

这样子, 从 最后求出最大公约数的那一层往前一直回溯, 我们就会得到最终的x和y的值

这个地方有一个边界,  也就是 当 a%b == 0的时候,    b* x' = gcd(a,b). x'等于1 y'可以取y' = 0;

下面可以举例

最后改方法用代码来表示

int gcd(int a,int b,int& x,int& y){
    if(b == 0){
        x = 1;y = 0;
        return a;
    }
    //根据x = y' , y = x' - (a/b)*y';
    //首先因为用的是&运算符,先保存上一次的x结果
    int c = gcd(b,b%a,x,y);
    int tp = x;
    x = y;    //将x置为 y'.
    y = tp - a/b*x;
    return c;
}

//以上代码可以简化为
void gcd(int a,int b,int& c,int& x,int &y){ //c为最大公约数
    if(b == 0){
        x = 1,y = 0;
        c = a;
    }
    gcd(b,a%b,c,y,x);
    y = y-a/b*x;
}

猜你喜欢

转载自blog.csdn.net/lala__lailai/article/details/81387968