当前位置:首页 > C++知识 > 正文内容

【算法】扩展欧几里得算法

亿万年的星光3年前 (2023-01-08)C++知识1818

一、欧几里得算法

我们前面学过求最大公约数的算法:欧几里得算法(又叫辗转相除法) ,一般缩写是gcd,在C++中经常写成如下形式:

int gcd(int a,int b)

 { 
     if(a%b==0)
         return b;
     else
         return gcd(b,a%b);
 }

原理就是代码中比较核心的 gcd(b,a%b),这个定理用文字描述就是:

用a除以b(这里是a>b,当然,在程序编程中,求两个数的最大公约数,可以不限a和b的大小,a<b也就是多一次循环)得到结果q和余数r,再用除数b除以余数r 再得到一个余数,再用除数除以余数,…如此循环,直到余数为0,那么此时的除数就是最大公因数。

想要证明gcd(a,b) = gcd(b,a%b),需要简单了解下面两个引理:

  • 若d是a和b的公约数,那么d也是b和c的公约数(c为a%b)

  • 若d是b和c的公约数(c为a%b),那么d也是a和b的公约数

这两个引理的是什么意思呢,拿第一个来说;

假设一个数d是a的因子,也就是a=m*d,同时也是b的因子,b=n*d,那么a%b = a-w*b =  (m-w*n)*d;

由此可得,a的因子集合、b的因子集合和c的因子集合是相同的;

然后利用上述定理当余数为0的时候,除数就是最大公约数;


二、扩展欧几里得算法

    从字面上看,扩展欧几里得算法就是把欧几里得算法进行了扩展,不仅能求a和b的最大公约数,还其他功能,比如:

  • 求ax+by=m的任意一组解,最小整数解。

  • 求模逆元(模反元素)


为了了解学习上面的公式,需要先了解一个裴属定理


裴属定理】:

对于任意正整数a,b,必有非零整数x,y,使得  ax+by= d。其中,d=gcd(a,b)。

显然有 ax` + by` = k * d ,即 x` =k * x  ,  y`= k* y 。

简言之:ax+by能够取到a和b的最大公约数的整数倍。

简单推论:

如果 a,b互质,即gcd(a,b)=1,则ax+by可以取到任意正整数。


知道了上面的定理,我们求ax+by=m就可以判断是否有解,如果有解,那么m一定是gcd的若干倍。

那么,参考的代码模板如下:

C语言版:

 int gcdEx(int a,int b,int*x,int*y)
{
    if(b==0)
    {
        *x=1,*y=0 ;
        return a ;
    }
    else 
    {
        int r=gcdEx(b,a%b,x,y);
        /* r = GCD(a, b) = GCD(b, a%b) */
        int t=*x ;
        *x=*y ;
        *y=t-a/b**y ;
        return r ;
    }
}

C++版:

// 求x, y,使得ax + by = gcd(a, b)
int exgcd(int a, int b, int &x, int &y)
{
    if (!b)
    {
        x = 1; y = 0;
        return a;   //到达递归边界开始向上一层返回
    }
    int d = exgcd(b, a % b, x, y);
    int temp=y;    
    y=x-(a/b)*y;
    x=temp;
    return d;
}


上面的这段代码的解释是:

首先,当递归到达边界时,余数b==0,除数a就是最大公约数,此时可以得出方程的一组解:

x=1, y=0   //   a*1+b*0= gcd(a,b)

注意在递归中永远都是先得到上一层的结果状态。

假设栈中当前层得到的解是x1,y1, 那么我们递归后带入下一层:

b*x1 + (a%b)*y1 = gcd(a,b)
 ->  b*x1 + (a- (a/b)*b ) *y1 =gcd(a,b)
 ->  a*y1 + b*(x1- (a/b) *y1) =gcd(a,b)

显然,由上一层的解x1,y1,可以推出下一层x,y的状态

x=y1
y=x1-(a/b)*y1


通解形式:

  • x=x0+b/gcd(a,b) * n  (相当于x每次可以增减:b/gcd的整数倍) 

  • y=y0+a/gcd(a,b) * n  (相当于y每次可以增减:a/gcd的整数倍)    《注意:x求出来后,y通常由x代入方程求得》

最小正整数解:

  • x=(x+b/gcd*n)%(b/gcd) = x%(b/gcd)     (b/gcd(a,b)应取正)

  • 若x<=0,则x+=b/gcd


应用:

  • 解不定方程

  • 求逆元

  • 求解线性同余方程

扫描二维码推送至手机访问。

版权声明:本文由青少年编程知识记录发布,如需转载请注明出处。

分享给朋友:

相关文章

【数论】龟速乘

【数论】龟速乘

我们前面一篇文章学习了快速幂。它可以解决两类问题:a^b,(a^b)%c对于第一类,我们可以使用递归法或者迭代法可以求出,为了计算的快,我们可以引入位运算操作,但是目前来看,无论怎么优化都不能超过lo...

【数论】杨辉三角

【数论】杨辉三角

一、起源 杨辉三角,是二项式系数在三角形中的一种几何排列。在欧洲,这个表叫做帕斯卡三角形。帕斯卡(1623----1662)是在1654年发现这一规律的,比杨辉要迟393年,比贾宪迟600年。杨辉三角...

【数据结构】栈的基本操作

0.前言上一篇中简单介绍了栈的定义,这一篇中介绍栈的基本用法,包含压栈,出栈,判断栈空,判断栈中元素个数等。下面进行详细介绍1.基本用法本文介绍的栈的主要操作,使用栈之前加入<stack>...

字符串的输入输出汇总

做字符串的题目的时候,经常会遇到输入输出不对的情况,这篇文章就简单总结一下字符串常见的输入输出。2.cin基本操作:#include<iostream> #include<cstd...

【入门篇】C++ 中变量的简单使用

【入门篇】C++ 中变量的简单使用

1.什么是变量”变量“通俗来讲就是能变的量。在程序设计中,变量是一个个不同类型的盒子,当盒子里装了苹果时,盒子就代表苹果,当然,我们需要给一个个盒子起不同的名字。像下面的图片一样,一个盒子,给他取一个...

【数论】二项式定理

【数论】二项式定理

一、基本概念上面这个式子就叫做二项式定理,又称牛顿二项式定理,该定理给出两个数之和的整数次幂诸如展开为类似项之和的恒等式。二项式定理可以推广到任意实数次幂,即广义二项式定理。 初中高中阶段比...