扩展欧几里得算法

1、思路

裴蜀定理(或贝祖定理)得名于法国数学家艾蒂安·裴蜀,说明了对任何整数a、b和它们的最大公约数d,关于未知数x和y的线性不定方程(称为裴蜀等式):
若a,b是整数,且gcd(a,b)=d,那么对于任意的整数x,y,ax+by=m中的m一定是d的倍数,特别地,一定存在整数x,y,使ax+by=d成立。如果a、b是整数,那么一定存在整数x、y使得ax+by=gcd(a,b)
它的一个重要推论是:a,b互质充分必要条件是存在整数x,y使ax+by=1.
那么贝祖定理的一个直接应用就是:如果ax+by=1有解,那么gcd(a,b)=1(将原公式两边同时除以gcd(a,b))。

扩展欧几里得算法用来解决这样一个问题:
给定两个非零的整数a和b,求一组整数解(x,y)使得ax+by = gcd(a,b)成立,其中gcd(a,b)表示a和b的最大公约数。(其中我们通过前面的贝祖定理可知解一定存在)
回忆我们知道的欧几里得算法,它总是把gcd(a,b)转化为求解gcd(b,a%b),而当b变为0时返回a,此时的a就等于gcd。
也就是说,欧几里得算法结束时变量a中存放的是gcd,变量b中存放的是0,因此此时显然有a × 1 + b × 0 = gcd成立,此时有x=1、y=0成立。
我们不妨利用上面的欧几里得算法的过程来计算x和y。目前已知的是递归边界成立时为x=1、y=0,需要想办法反推出最初始的x和y。

(1)用于求解方程 的解,

当b=0时, ,可以得到x=1,y=0
当b不为0时,
已知                                         
                                                   
对于a%b,有,(式子中为整除)
                                                    
递归到下一层,有:
                                                    
                                                    
                                                    ay^{'}+b(x^{'}-⌊\frac{a}{b}⌋y^{'})=ax+by
可得,
                                                    
                                                    

(2)对于求解一般方程ax+by=c

设d=gcd(a,b),则其有解当且仅当 d|c(d能整除c,即c是d的倍数)     
求解方法如下:
用扩展欧几里得求出  的解
a(x0∗c/d)+b(y0∗c/d)=c
则有                                             
                                                    
对比式子ax+by=c,我们可以得到一个特解
                                                           
                                                                             
而通解 = 特解 + 齐次解
齐次解为 方程ax+by=0的解



则方程的通解为:
                                                    
                                                            

(3)求解一次同余方程ax≡b(mod m)

对于b%m,我们可以转化成
                                                   
那么原式就可以化为
                                                   
                                                   
有解条件为 gcd(a,m)|b,然后用扩展欧几里得求解
特别的 当 b=1且 a与m互质时 则所求的x即为a的逆元

2、代码模板:


#include<iostream>
using namespace std;
const int N=1e5+10;
/*
int exgcd(int a,int b,int &x,int &y)//返回gcd(a,b) 并求出解(引用带回)
{
    //欧几里得算法结束时,变量a中存放的是gcd,变量b中存放的是0,因此此时显然有a × 1 + b × 0 = gcd成立。
    if(!b)//当b为0时,它总是把gcd(a,b)转化为求解gcd(b,a%b),而当b变为0时返回a,此时的a就等于gcd。
    {
        x=1,y=0;
        return a;
    }
    int x1,y1;
    int d=exgcd(b,a%b,x1,y1);//递归求最大公约数, 求完后d就是最大公约数,
    x=y1;
    y=x1-a/b*y1;
    return d;
}
*/
int exgcd(int a,int b,int &x,int &y)//返回gcd(a,b) 并求出解(引用带回)
{
    //欧几里得算法结束时,变量a中存放的是gcd,变量b中存放的是0,因此此时显然有a × 1 + b × 0 = gcd成立。
    if(!b)//当b为0时,它总是把gcd(a,b)转化为求解gcd(b,a%b),而当b变为0时返回a,此时的a就等于gcd。
    {
        x=1,y=0;
        return a;
    }
    int d=exgcd(b,a%b,y,x);//递归求最大公约数, 求完后d就是最大公约数,
    y-=(a/b)*x;//公式是y1=x2-(a/b)*y2,由x1=y2转化为 y1=x2-(a/b)*x,又由x2为y1,所有化简为y-=(a/b)*x
    return d;
}

int main()
{
    int n;
    scanf("%d",&n);
    while(n--)
    {
        int a,b,x,y;
        scanf("%d %d",&a,&b);
        exgcd(a,b,x,y);
        printf("%d %d\n",x,y);
    }
    return 0;
}


















全部评论

相关推荐

牛客73617529...:无端端被你骂一句
点赞 评论 收藏
分享
鬼迹人途:你去投一投尚游游戏,服务器一面,第一个图算法,做完了给你一个策略题,你给出方案他就提出低概率问题,答不上当场给你挂
点赞 评论 收藏
分享
05-26 10:24
门头沟学院 Java
qq乃乃好喝到咩噗茶:其实是对的,线上面试容易被人当野怪刷了
找工作时遇到的神仙HR
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务