欧几里德算法非常简洁,明了,通俗易懂。
m ( m > 0 ) m(m > 0) m ( m > 0 ) 整除 n n n 记作 m ∣ n m \vert n m ∣ n ,其定义为存在一个整数 k k k 使得 k m = n km = n k m = n 。
欧几里德算法 两个数 a a a 和 b b b 的最大公因子(greatest common divisior) 是能整除它们两者的最大整数。欧几里德算法(又称辗转相除法)用于计算两个整数 a a a ,b b b 的最大因子。我们记 gcd ( a , b ) \gcd(a,b) g cd( a , b ) 为自然数 a a a 与 b b b 的最大公因子。特别的,有 gcd ( 0 , n ) = 0 \gcd(0, n) = 0 g cd( 0 , n ) = 0 ,因为任何整数都能整除 0 0 0 。
内容 gcd ( a , b ) = { a , b = 0 gcd ( b , a mod b ) , b ≠ 0
\gcd(a, b)=
\begin{cases}
a, & b = 0\\
\gcd(b, a\bmod b), & b\neq 0
\end{cases}
g cd( a , b ) = { a , g cd( b , a modb ) , b = 0 b ≠ 0 证明 首先考虑边界情况,因为 gcd ( 0 , n ) = n \gcd(0, n) = n g cd( 0 , n ) = n ,所以这个边界显然是正确的。
接着考虑一般情况,设 a a a 除以 b b b 得到的商为 p p p 余数为 q q q ,则有
a = b ⋅ p + q
a = b \cdot p + q
a = b ⋅ p + q 考虑 gcd ( b , q ) \gcd(b, q) g cd( b , q ) ,两个可以被 gcd ( b , q ) \gcd(b, q) g cd( b , q ) 整除的数相加得到 a a a ,可知 a a a 一定可以被 gcd ( b , q ) \gcd(b, q) g cd( b , q ) 整除。所以 gcd ( b , q ) \gcd(b, q) g cd( b , q ) 既能整除 a a a 又能整除 b b b 。因为 gcd ( b , q ) \gcd(b, q) g cd( b , q ) 同时整除 a , b , q a, b, q a , b , q ,所以 gcd ( b , q ) \gcd(b, q) g cd( b , q ) 也能整除 gcd ( a , b ) \gcd(a, b) g cd( a , b ) 。这就说明
gcd ( b , q ) ∣ gcd ( a , b )
\gcd(b, q)\mid \gcd(a, b)
g cd( b , q ) ∣ g cd( a , b ) 变化一下之前的式子
q = a − b ⋅ p
q = a - b \cdot p
q = a − b ⋅ p 同理可得 gcd ( a , b ) \gcd(a, b) g cd( a , b ) 同时整除 a , b , q a, b, q a , b , q ,所以有
gcd ( a , b ) ∣ gcd ( b , q )
\gcd(a, b)\mid \gcd(b, q)
g cd( a , b ) ∣ g cd( b , q ) 结合两个式子,就能得证
gcd ( a , b ) = gcd ( b , a ∣ b ) , b ≠ 0
\gcd(a, b) = \gcd(b, a\mid b), \quad b\neq 0
g cd( a , b ) = g cd( b , a ∣ b ) , b ≠ 0 上面的推导,都是基于 a ≥ b a \ge b a ≥ b 的,那么要是
,怎么办呢?不用担心,其实它一步就会变成 gcd ( b , a ) \gcd(b, a) g cd( b , a ) 。
复杂度 接下来我们估算欧几里德算法的复杂度。我们不妨设 a > b a > b a > b 。分两种情况考虑:
若 b > a 2 b > \frac a 2 b > 2 a ,那么 a mod b = a − b < a 2 a\bmod b = a - b < \frac a 2 a modb = a − b < 2 a
若 b ≤ a 2 b \le \frac a 2 b ≤ 2 a ,那么 a mod b < b < a 2 a\bmod b < b < \frac a 2 a modb < b < 2 a
因此经过至多 2 次递归之后,第二个参数要小于原来的一半。所以其复杂度为 O ( log max ( a , b ) ) O(\log\max(a, b)) O ( log max ( a , b ) ) ,足以证明欧几里德算法是非常高效的了。
扩展欧几里德算法 用途 扩展欧几里德算法是对欧几里德算法的扩展,它可以用来求解形如 a x + b y = c ( a , b , c ∈ Z ) ax + by = c(a, b, c \in Z) a x + b y = c ( a , b , c ∈ Z ) 的方程的一组整数解。
方程解的讨论 事实上,只有当 gcd ( a , b ) ∣ c \gcd(a, b)\mid c g cd( a , b ) ∣ c 时,此方程才有整数解,下面简短给出证明:
a x + b y = c
ax + by = c
a x + b y = c 同时除以 gcd ( a , b ) \gcd(a, b) g cd( a , b )
a gcd ( a , b ) x + b gcd ( a , b ) y = c gcd ( a , b )
\frac{a}{\gcd(a, b)}x + \frac{b}{\gcd(a, b)}y = \frac{c}{\gcd(a, b)}
g cd( a , b ) a x + g cd( a , b ) b y = g cd( a , b ) c 方程左边的系数显然还是整数,所以方程右边必然要为整数,方程才可能有解。可见只有当 gcd ( a , b ) ∣ c \gcd(a, b)\mid c g cd( a , b ) ∣ c 时,此方程才有整数解。
实现 那么如何实现扩展欧几里德算法呢,我们从欧几里德算法给我们提供的等式来入手。
我们记 e x g c d ( a , b , x , y ) \mathrm{exgcd}(a, b, x, y) e x g c d ( a , b , x , y ) 为求解方程 a x + b y = gcd ( a , b ) ax + by = \gcd(a, b) a x + b y = g cd( a , b ) 的函数,其中形式参数 x , y x, y x , y 均为引用类型。
一样先考虑边界情况,当 b = 0 b = 0 b = 0 时,原方程可化为 a x = gcd ( a , 0 ) ax = \gcd(a, 0) a x = g cd( a , 0 ) ,解得 { x = 1 y = 0 \begin{cases} x = 1 \\y = 0 \end{cases} { x = 1 y = 0 。
对于一般情况,设 a ′ = b , b ′ = a mod b a' = b, b' = a\bmod b a ′ = b , b ′ = a modb ,则考虑方程
a ′ x ′ + b ′ y ′ = gcd ( a ′ , b ′ ) = gcd ( b , a mod b )
a'x' + b'y' = \gcd(a', b') = \gcd(b, a\bmod b)
a ′ x ′ + b ′ y ′ = g cd( a ′ , b ′ ) = g cd( b , a modb ) 以及我们要求解的方程
a x + b y = gcd ( a , b )
ax + by = \gcd(a, b)
a x + b y = g cd( a , b ) 有恒等式 gcd ( a , b ) = gcd ( b , a mod b ) \gcd(a, b) = \gcd(b, a\bmod b) g cd( a , b ) = g cd( b , a modb ) ,所以
a x + b y = a ′ x ′ + b ′ y ′ = b x ′ + ( a mod b ) y ′ = b x ′ + ( a − ⌊ a b ⌋ b ) y ′
ax + by = a'x' + b'y' = bx' + (a\bmod b)y' = bx' + (a - \lfloor\frac a b\rfloor b)y'
a x + b y = a ′ x ′ + b ′ y ′ = b x ′ + ( a modb ) y ′ = b x ′ + ( a − ⌊ b a ⌋ b ) y ′ 整理得到
a x + b y = a y ′ + b ( x ′ − ⌊ a b ⌋ y ′ )
ax + by = ay' + b(x' - \lfloor\frac a b\rfloor y')
a x + b y = a y ′ + b ( x ′ − ⌊ b a ⌋ y ′ ) 其中 x ′ , y ′ x',y' x ′ , y ′ 为方程 a ′ x ′ + b ′ y ′ = gcd ( a ′ , b ′ ) a'x' + b'y' = \gcd(a', b') a ′ x ′ + b ′ y ′ = g cd( a ′ , b ′ ) 的解。我们比对两个方程的系数,发现我们只要求出了 x ′ x' x ′ 和 y ′ y' y ′ ,我们就能求出 x x x 以及 y y y ,它们对应的关系为
{ x = y ′ y = x ′ − ⌊ a b ⌋ y ′
\begin{cases}
x = y'\\
y = x' - \lfloor\frac a b\rfloor y'
\end{cases}
{ x = y ′ y = x ′ − ⌊ b a ⌋ y ′ 由此我们成功得到递归式以及边界条件,可以求解方程了,每次只需要递归 e x g c d ( b , a mod b , x , y ) \mathrm{exgcd}(b, a\bmod b, x, y) e x g c d ( b , a modb , x , y ) ,然后处理一下即可得到方程 a x + b y = gcd ( a , b ) ax + by = \gcd(a, b) a x + b y = g cd( a , b ) 的一组解。
对于求解方程 a x + b y = c ( gcd ( a , b ) ∣ c ) ax + by = c(\gcd(a, b)\mid c) a x + b y = c ( g cd( a , b ) ∣ c ) ,只需求解出方程 a x + b y = gcd ( a , b ) ax + by = \gcd(a, b) a x + b y = g cd( a , b ) 的一组解,将 x , y x, y x , y 分别乘上 c gcd ( a , b ) \frac c {\gcd(a, b)} g cd( a , b ) c 即可得到 a x + b y = c ( gcd ( a , b ) ∣ c ) ax + by = c(\gcd(a, b)\mid c) a x + b y = c ( g cd( a , b ) ∣ c ) 的一组解。
实战 Vijos 1279 题目
数学题,可证明答案为 a + b − gcd ( a , b ) a + b - \gcd(a, b) a + b − g cd( a , b ) ,也可根据这经典的图求解。
long long gcd ( int a , int b ) {
if ( b == 0 ) return 0 ;
return a / b * b + gcd ( b , a % b );
}