扩展欧几里得的推导与代码实现

引言 : 裴蜀定理(定义摘自oi wiki)

定义

  设整数a,b是不全为0的整数,则存在整数x,y,使得 ax+by = gcd(a,b) 

  

证明

   1.若a,b有一个数为0,则x取1即可成立

  2.若a,b都为正整数,gcd(a,b) 为a,b的共同因子

   所以 a%gcd(a,b) = b%gcd(a,b) = 0

   由(m+n)%p = m%p+n%p

   可以得出 (ax+by)%gcd(a,b) = ax%gcd(a,b)+by%(gcd,a,b) = 0+0 = 0  得证

 

回到今天的主角扩展欧几里得算法(部分借鉴知乎用户忘忧北萱草的文章)

传统欧几里得算法是用辗转相除算出a,b的最大公约数

扩展欧几里得则是可以在既算出最大公约数的同时,算出ax+by = gcd(a,b) 中的(x,y)

 

在欧几里得算法中,递归根据的是gcd(a,b) = (b,a%b) = (b,a-b[a/b])  在扩欧里也会用到这个结论

设两组解(x,y) , (x1,y1)  根据裴蜀定理可得ax+by = gcd(a,b) bx1+(a-b[a/b])y1 = (b,a-b[a/b])

由于(a,b) = (b,a-b[a/b])  则将两个式子联立求解得  a(x-y1) + b(y-(x1-y1[a/b])) = 0

我们希望这个式子对于所有解集(x,y) 都成立 于是有 x = y1  y = x1-y1[a/b] 

此时求解(x,y)已经变成了求解(x1,y1),继续递归直到求解完成。递归结束条件为b=0,此时x=1,y=0

 

代码实现:

  int exgcd(int a, int b, int& x, int& y)  //返回的是gcd(a,b) x,y要传引用
  {
    if(a < b) return exgcd(b, a, y, x);  
    if(b == 0)          //递归的结束条件是 b==0
    {
      x = 1; y = 0;
      return a;
    }
    else
    {
      int x1;
      int d = exgcd(b, a % b, x1, x);  //exgcd(a,b,x,y) 的实质是一位置乘三位置 + 二位置*四位置 = gcd(一位置,二位置)

      y = x1 - a / b * x;       //根据前文第三处黑体字可知  递归函数的三位置应该是x1,四位置应该是y1

      return d;           //因为x=y1 所以四位置是x
    }
  }

 

posted @ 2023-05-06 16:48  拾墨、  阅读(17)  评论(0编辑  收藏  举报