6.2. 辗转相除法

1. 辗转相除法, 又名欧几里德算法(Euclidean algorithm),是求最大公约数的一种方法。它的具体做法是:用较大数除以较小数,再用出现的余数(第一余数)去除除数,再用出现的余数(第二余数)去除第一余数,如此反复,直到最后余数是0为止。如果是求两个数的最大公约数,那么最后的除数就是这两个数的最大公约数。

步骤:

两个数的最大公约数是指能同时整除它们的最大正整数。
设两数为a、b(a≥b),求a和b最大公约数的步骤如下
(1)用a除以b(a≥b),a / b = q...r1;
(2)若r1 == 0,则gcd(a,b) = q;
(3)若r1 != 0,则b / r1 = q..r2;
(4)若r2 == 0,则gcd(a,b) = r1;
(5)若r2 != 0, 则重复上述(3),(4)步骤;

实际过程:

(1) a / b = q1 ... r1
   a = q1 * b + r1 b = b
   if: r1 == 0 , gcd(a, b) = b

(2) b / r1 = q2 ... r2
   b = q2 * r1 + r2 r1 = r1
   if: r2 == 0 , gcd(b, r1) = r1;
   a = q1*q2*r1 + r1 b = q2*r1
   gcd(a, b) = r1

复杂度: 在O(log max(a,   b)) 以内

代码:

 int gcd (int a, int b) {
     return !b ? a : gcd (b, a % b);
 }

2.扩展欧几里德算法

  扩展欧几里德算法是用来在已知 a, b 求解一组 x, y ,使它们满足贝祖等式:

ax + by = gcd(a, b)(解一定存在)。扩展欧几里德常用在求解模线性方程及方程组中。

理解 x 和 y:

  已知了 ax + by = gcd(a, b) 一定是有解的 (数论相关定理可证)。

  1. 显然当 b = 0,gcd(a, b) = a。 此时 x = 1, y = 0;

  2. a > b > 0 时:

    设 a x1 + b y1 = gcd (a, b); 

     b x2 + (a mod b) y2 = gcd (b, a mod b);

             根据欧几里德原理  gcd(a, b) = gcd(b, a mod b);

   则 a x1 + b y1 = b x2 + (a mod b) y2;

   即: a x1 + b y1 = b x2 + (a - [a / b] * b) y2 = a y2 + b x2 - [a/b] * b y2;

    (这里说明一下: a mod b = a - [a / b] * b       [a / b]  代表取整 )

   那么 a x1 + b y1 = a y2 + b (x2 - [a / b] * y2).

   结论: x1 = y2; y1 = x2 - [a / b] * y2.

   这样就找到了求解x1 , y1 的方法。

代码:

int extgcd (int a, int b, int& x, int& y) {
    
    int d = a;
    if (b != 0) {
        d = extgcd (b, a % b, y, x);
        y -= (a/ b) * x;
    }
    else {
        x = 1;
        y = 0;
    }
    return d;
} 

这里返回的d 就是gcd(a, b) 的值。

关于解 x 和 y 的大小:

  事实上,如果 ab ≠ 0 , 可知道 |x| ≤ b 且 |y| ≤ a.

猜你喜欢

转载自www.cnblogs.com/astonc/p/10656932.html