扩展欧几里得算法

欧几里得算法中,计算 x, y 的最大公约数的方法是辗转相除,例如:
gcd (26, 15)
26 % 15 = 1 ... 11
15 % 11 = 1 ... 4
11 % 4 = 2 ... 3
4 % 3 = 1 ... 1
3 % 1 = 3 ... 0

可知,gcd (26, 15) = 1
如果 gcd(x, y) = r,那么有 ax + by = r,可以看出,上面的步骤实际上是可以直接得出 a, b 的:

26 % 15 = 1 ... 11 => 11 = 26 - 15 1 1 -1
15 % 11 = 1 ... 4 => 4 = 15 - 11 = 15 - (26 - 15) = -26 + 2*15 1 -1 2
11 % 4 = 2 ... 3 => 3 = 11 - 4*2 = (26 - 15) - (-26 + 15) * 2 = 3*26 - 5*15 2 3 -5
4 % 3 = 1 ... 1 => 1 = 4 - 3 = (-26 + 2*15) - (3*26 - 5*15) = -4*26 + 7*15 1 -4 7
3 % 1 = 3 ... 0

在每一轮,我们都可以得到一个模的表达式为:ri = aix + biy
如果不考虑第一轮和第二轮,那么ai 和 bi 可以表示为(qi 为每一轮得到的商):
ai = ai-2 - qi * ai-1
bi = bi-2 - qi * bi-1

证明如下:
输入:x,y,则有如下:
x/y=q1…..r1 =>r1=x-q1*y
y/r1=q2…r2 =>r2=y-q2*r1=y-q2*(x-q1*y)=-q2*x+(1+q2*q1)*y
r1/r2=q3…r3 =>r3=r1-q3*r2=(x-q1*y)-q3*(-q2*x+(1+q2*q1)*y)
=(1+q2*q3)x+(-q1-q3*(1+q2*q3))*y
则可以看出有:a3=1+q3*q2=a1-q3*a2
B3=b1-q3*b2
由此可以推测出:
ai = ai-2 - qi * ai-1
bi = bi-2 - qi * bi-1
但是a1,b1,a2,b2比较特别:
a1=1=a-1 – q1*a0
b1=-q1=b-1 – q1*b0
由此我们可以知道a-1=1,a0=0,b-1=0,b0=1即可满足。所以这个是初试条件。
现在来考虑第一轮和第二轮,按照上面的公式,可以认为

a-1 = 1, b-1 = 0
a0 = 0, b0 = 1

有了这两对预设值,上面的两个公式就成立了

求逆元,由上面可以看出,gcd(x, y) = 1 的时候
如果 ax + by = 1,那么 ax = -by + 1 => ax = 1 (mod b)
这时候,a 即是 x 的逆元

#include <stdio.h>

  int gcd (int x, int y, int *a1, int *a2, int *b1, int *b2)
  {
    int q, r, a, b;

    q = x / y;
    r = x % y;
    a = *a2 - q*(*a1);
    b = *b2 - q*(*b1);

    if (0 == r)
      {
        return y;
      }

    *a2 = *a1;
    *b2 = *b1;

    *a1 = a;
    *b1 = b;

    return gcd (y, r, a1, a2, b1, b2);
  }

  int main ()
  {
   int x, y, a1, a2, b1, b2, r;

    scanf("%d %d", &x, &y);

    a1 = 0;
    a2 = 1;
    b1 = 1;
    b2 = 0;

    r = gcd (x, y, &a1, &a2, &b1, &b2);

    printf ("%d = (%d) * (%d) + (%d) * (%d)
",
            r, a1, x, b1, y);

    return 0;
  }


输入样例:
7 160
输出:
//7 的 mod 160 ==1 的逆元为 23
世上无难事,只要肯登攀。
原文地址:https://www.cnblogs.com/littlehoom/p/3438934.html