为了介绍扩展欧几里得,我们先介绍一下贝祖定理

           即如果a、b是整数,那么一定存在整数x、y使得ax+by=gcd(a,b)。

换句话说,如果ax+by=m有解,那么m一定是gcd(a,b)的若干倍。(可以来判断一个这样的式子有没有解)

有一个直接的应用就是 如果ax+by=1有解,那么gcd(a,b)=1;

要求出这个最大公因数gcd(a,b),我们最容易想到的就是古老悠久而又相当强大的辗转相除法:

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

但是,对于上面的式子ax+by=m来说,我们并不仅仅想要知道有没有解,而是想要知道在有解的情况下这个解到底是多少。

所以,扩展欧几里得

        当到达递归边界的时候,b==0,a=gcd(a,b) 这时可以观察出来这个式子的一个解:a*1+b*0=gcd(a,b),x=1,y=0,注意这时的a和b已经不是最开始的那个a和b了,所以我们如果想要求出解x和y,就要回到最开始的模样。

        初步想法:由于是递归的算法,如果我们知道了这一层和上一层的关系,一层一层推下去,就可以推到最开始的。类似数学上的数学归纳法。

        假设当前我们在求的时a和b的最大公约数,而我们已经求出了下一个状态:b和a%b的最大公因数,并且求出了一组x1和y1使得                          b*x1+(a%b)*y1=gcd

(注意在递归算法中,永远都是先得到下面一个状态的值)

这时我们可以试着去寻找这两个相邻状态的关系:

首先我们知道:a%b=a-(a/b)*b;带入:

b*x1 + (a-(a/b)*b)*y1

= b*x1 + a*y1 – (a/b)*b*y1

= a*y1 + b*(x1 – a/b*y1) = gcd   发现 x = y1 , y = x1 – a/b*y1

这样我们就得到了每两个相邻状态的x和y的转化,就可以在求gcd的同时对x和y进行求值了hiahia

--------------------------------------------------------------我是分割线哇---------------------------------------------------------------

板子板子:

#include<iostream>
#include<cstdio>
#include<cmath>

using namespace std;

int exgcd(int a,int b,int &x,int &y)//扩展欧几里得算法
{
    if(b==0)
    {
        x=1;y=0;
        return a;  //到达递归边界开始向上一层返回
    }
    int r=exgcd(b,a%b,x,y);
    int temp=y;    //把x y变成上一层的
    y=x-(a/b)*y;
    x=temp;
    return r;     //得到a b的最大公因数
}

呼呼

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐