扩展欧几里得算法超详解

 

目录

引言

欧几里得算法(gcd)

代码模板:

扩展欧几里得(exgcd)

代码模板:

通解形式为:

最小正整数解:


引言

什么是扩展欧几里得,听起来好高深,别急先从欧几里得下手;

欧几里得算法(gcd)

  • 欧几里得算法的用处:求两个数的最大公约数;
  • 原理:辗转相除法;

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

辗转相除法能够成立基于以下定理:

  • Theorem: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%d = a-w*b =  (m-w*n)*d;

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

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

可是为什么会出现余数为0的情况呢,为什么这个时候除数是最大公约数?????

按照辗转相除法的方法如此循环下去,
  因为每次的余数r肯定小于除数n
  那么相当于每次的被除数(变为上次的除数)变小,
  除数(变为上次的余数)也变小,而公因数的集合一直不变
 
  也就是被除数和除数越来越小,而二者所包含的公共公因数集合又不
  变,这样下去,除数总有一次会变为最大的公因数。

 

代码模板:

int gcd(int a, int b)
{
    return b ? gcd(b, a % b) : a;
}
或者使用c++函数 __gcd();

 

 

扩展欧几里得(exgcd)

顾名思义extend—gcd,就是在欧几里得算法的过程基础上进行修改;

扩展欧几里得用途:

  • 判断方程ax+by=m是否有解
  • 求ax+by=m的任意一组解、通解、最小整数解

首先除了了解过欧几里得算法,还要知道裴属定理:

  • ax+by=gcd(a , b)

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

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

 难道仅仅局限于知道是否有解么?当然好奇的人类是想知道在有解的情况下,这个解是多少,也就是x和y的值是多少;

扩展欧几里得就能实现(根据模板讲解吧):

代码模板:

// 求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;    //推出这一层的x,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

于是相邻的两个层之间的状态关系就出来了,ey~

 

由上述模板可以求出方程 ax+by=gcd(a,b) 的任意一组解x0,y0;那么方程ax+by=k的通解的形式是什么样的呢?

( ax+by=k 中的k一定是gcd(a,b)的倍数,方程才会有解)

具体推导:扩展欧几里得求通解、最小正整数解 

因为由 ax+by=gcd(a,b) 变成 ax+by=k 方程扩大了 k/gcd(a,b)倍,所以通过扩欧求出来的x0,y0也扩大了相同的倍数

x0=x0* (k/gcd(a,b))             y0=y0* (k/gcd(a,b))  

通解形式为:

  • 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

 

你可能感兴趣的:(基础算法——数论)