欧几里德算法与扩展欧几里德算法

Published on 2015-11-03

欧几里德算法非常简洁,明了,通俗易懂。

m(m>0)m(m > 0) 整除 nn 记作 mnm \vert n,其定义为存在一个整数 kk 使得 km=nkm = n

欧几里德算法

两个数 aabb最大公因子(greatest common divisior)是能整除它们两者的最大整数。欧几里德算法(又称辗转相除法)用于计算两个整数 aabb 的最大因子。我们记 gcd(a,b)\gcd(a,b) 为自然数 aabb 的最大公因子。特别的,有 gcd(0,n)=0\gcd(0, n) = 0,因为任何整数都能整除 00

内容

gcd(a,b)={a,b=0gcd(b,amodb),b0 \gcd(a, b)= \begin{cases} a, & b = 0\\ \gcd(b, a\bmod b), & b\neq 0 \end{cases}

证明

首先考虑边界情况,因为 gcd(0,n)=n\gcd(0, n) = n,所以这个边界显然是正确的。

接着考虑一般情况,设 aa 除以 bb 得到的商为 pp 余数为 qq,则有

a=bp+q a = b \cdot p + q

考虑 gcd(b,q)\gcd(b, q) ,两个可以被 gcd(b,q)\gcd(b, q) 整除的数相加得到 aa,可知 aa 一定可以被 gcd(b,q)\gcd(b, q) 整除。所以 gcd(b,q)\gcd(b, q) 既能整除 aa 又能整除 bb。因为 gcd(b,q)\gcd(b, q) 同时整除 a,b,qa, b, q ,所以 gcd(b,q)\gcd(b, q) 也能整除 gcd(a,b)\gcd(a, b)。这就说明

gcd(b,q)gcd(a,b) \gcd(b, q)\mid \gcd(a, b)

变化一下之前的式子

q=abp q = a - b \cdot p

同理可得 gcd(a,b)\gcd(a, b) 同时整除 a,b,qa, b, q,所以有

gcd(a,b)gcd(b,q) \gcd(a, b)\mid \gcd(b, q)

结合两个式子,就能得证

gcd(a,b)=gcd(b,ab),b0 \gcd(a, b) = \gcd(b, a\mid b), \quad b\neq 0

上面的推导,都是基于 aba \ge b 的,那么要是 ,怎么办呢?不用担心,其实它一步就会变成 gcd(b,a)\gcd(b, a)

复杂度

接下来我们估算欧几里德算法的复杂度。我们不妨设 a>ba > b。分两种情况考虑:

  1. b>a2b > \frac a 2 ,那么 amodb=ab<a2a\bmod b = a - b < \frac a 2
  2. ba2b \le \frac a 2 ,那么 amodb<b<a2 a\bmod b < b < \frac a 2

因此经过至多 2 次递归之后,第二个参数要小于原来的一半。所以其复杂度为 O(logmax(a,b)) O(\log\max(a, b)) ,足以证明欧几里德算法是非常高效的了。

扩展欧几里德算法

用途

扩展欧几里德算法是对欧几里德算法的扩展,它可以用来求解形如 ax+by=c(a,b,cZ)ax + by = c(a, b, c \in Z) 的方程的一组整数解。

方程解的讨论

事实上,只有当 gcd(a,b)c\gcd(a, b)\mid c 时,此方程才有整数解,下面简短给出证明:

ax+by=c ax + by = c

同时除以 gcd(a,b)\gcd(a, b)

agcd(a,b)x+bgcd(a,b)y=cgcd(a,b) \frac{a}{\gcd(a, b)}x + \frac{b}{\gcd(a, b)}y = \frac{c}{\gcd(a, b)}

方程左边的系数显然还是整数,所以方程右边必然要为整数,方程才可能有解。可见只有当 gcd(a,b)c\gcd(a, b)\mid c 时,此方程才有整数解。

实现

那么如何实现扩展欧几里德算法呢,我们从欧几里德算法给我们提供的等式来入手。

我们记 exgcd(a,b,x,y)\mathrm{exgcd}(a, b, x, y) 为求解方程 ax+by=gcd(a,b)ax + by = \gcd(a, b) 的函数,其中形式参数 x,yx, y 均为引用类型。

一样先考虑边界情况,当 b=0b = 0 时,原方程可化为 ax=gcd(a,0)ax = \gcd(a, 0),解得 {x=1y=0\begin{cases} x = 1 \\y = 0 \end{cases}

对于一般情况,设 a=b,b=amodba' = b, b' = a\bmod b ,则考虑方程

ax+by=gcd(a,b)=gcd(b,amodb) a'x' + b'y' = \gcd(a', b') = \gcd(b, a\bmod b)

以及我们要求解的方程

ax+by=gcd(a,b) ax + by = \gcd(a, b)

有恒等式 gcd(a,b)=gcd(b,amodb) \gcd(a, b) = \gcd(b, a\bmod b) ,所以

ax+by=ax+by=bx+(amodb)y=bx+(aabb)y ax + by = a'x' + b'y' = bx' + (a\bmod b)y' = bx' + (a - \lfloor\frac a b\rfloor b)y'

整理得到

ax+by=ay+b(xaby) ax + by = ay' + b(x' - \lfloor\frac a b\rfloor y')

其中 x,yx',y' 为方程 ax+by=gcd(a,b)a'x' + b'y' = \gcd(a', b') 的解。我们比对两个方程的系数,发现我们只要求出了 xx'yy',我们就能求出 xx 以及 yy,它们对应的关系为

{x=yy=xaby \begin{cases} x = y'\\ y = x' - \lfloor\frac a b\rfloor y' \end{cases}

由此我们成功得到递归式以及边界条件,可以求解方程了,每次只需要递归 exgcd(b,amodb,x,y)\mathrm{exgcd}(b, a\bmod b, x, y),然后处理一下即可得到方程 ax+by=gcd(a,b)ax + by = \gcd(a, b) 的一组解。

对于求解方程 ax+by=c(gcd(a,b)c)ax + by = c(\gcd(a, b)\mid c),只需求解出方程 ax+by=gcd(a,b)ax + by = \gcd(a, b) 的一组解,将 x,yx, y 分别乘上 cgcd(a,b) \frac c {\gcd(a, b)} 即可得到 ax+by=c(gcd(a,b)c)ax + by = c(\gcd(a, b)\mid c) 的一组解。

实战

Vijos 1279

题目

数学题,可证明答案为 a+bgcd(a,b)a + b - \gcd(a, b),也可根据这经典的图求解。

long long gcd(int a, int b) {
    if(b == 0) return 0;
    return a / b * b + gcd(b, a % b);
}