本算法基于欧几里得算法故称为扩展欧几里得算法。
该算法最常见的使用情况为:求解线性同余方程 a × x ≡ c ( m o d b ) a\times x \equiv c(mod\ b) a×x≡c(mod b)。
在解这个方程前,我们先来思考一个问题:如何快速解方程 a × x + b × y = g c d ( a , b ) a \times x + b\times y = gcd(a , b) a×x+b×y=gcd(a,b)。
我们引入一个定理:裴蜀定理。它说明对于任意整数 a , b a,b a,b,存在一对整数 x , y x , y x,y,满足 a x + b y = c ax+by = c ax+by=c。
这也就说明求解该方程式是可行的。
同时,我们可以很容易想到。当b = 0时,一定有一组特解: x = 1 , y = 0 x = 1,y = 0 x=1,y=0,而当我们计算 g c d ( a , b ) gcd(a , b) gcd(a,b)时,如果用欧几里得算法,一定会产生 b = 0 b = 0 b=0的情况。所以我们可以用欧几里得算法从 b = 0 b = 0 b=0的情况递归得到所求的一组特解。同时,对于任意一个特解,可以得到通解式: x = x 0 + m × k , 其 中 m 为 模 数 x = x_0 +m\times k,其中m为模数 x=x0+m×k,其中m为模数(利用同余的定义可以证明该式的正确性)。这就是扩展欧几里得算法的思路。
言归正传,我们可以将
a
×
x
≡
c
(
m
o
d
b
)
a\times x\equiv c(mod\ b)
a×x≡c(mod b)转换为
a
×
x
=
b
+
c
×
k
(
k
∈
Z
)
a\times x = b +c\times k(k\in Z)
a×x=b+c×k(k∈Z)移项得
a
×
x
+
(
−
b
)
×
k
=
c
a\times x + (-b) \times k = c
a×x+(−b)×k=c。因为实际上我们只需要求
x
x
x的值即可,所以可以把
−
b
-b
−b看成
b
b
b那么原式就变成了
a
×
x
+
b
×
y
=
c
a \times x + b\times y = c
a×x+b×y=c。
然后,我们考虑当
a
×
x
+
b
×
y
=
c
a \times x + b\times y = c
a×x+b×y=c的时候该怎么办呢?很明显,当
c
c
c为
g
c
d
(
a
,
b
)
gcd(a , b)
gcd(a,b)的倍数时,该式与上述式子没有本质区别,而当
c
c
c不为
g
c
d
(
a
,
b
)
gcd(a, b)
gcd(a,b)的倍数时,
x
x
x是无解的。
当然,对于
a
×
x
+
b
×
y
=
c
a \times x + b\times y = c
a×x+b×y=c的情况直接用扩展欧几里得算法是没法求出特解的,因为扩展欧几里得算法实质上解的是
a
×
x
+
b
×
y
=
g
c
d
(
a
,
b
)
a \times x + b\times y = gcd(a , b)
a×x+b×y=gcd(a,b)的解。
因此,我们将
c
c
c先换为
g
c
d
(
a
,
b
)
gcd(a , b)
gcd(a,b),求出一组解,而
a
×
x
+
b
×
y
=
g
c
d
(
a
,
b
)
a \times x + b\times y = gcd(a , b)
a×x+b×y=gcd(a,b)相当于是将
a
×
x
+
b
×
y
=
c
a \times x + b\times y = c
a×x+b×y=c的等号两边同时除以
c
÷
g
c
d
(
a
,
b
)
c\div gcd(a ,b)
c÷gcd(a,b)。
所以此时将
x
x
x的值乘上一个
c
÷
g
c
d
(
a
,
b
)
c\div gcd(a ,b)
c÷gcd(a,b)即可求出
a
×
x
+
b
×
y
=
c
a \times x + b\times y = c
a×x+b×y=c的一组特解。而它的通解就是
x
=
x
0
×
c
g
c
d
(
a
,
b
)
+
c
g
c
d
(
a
,
b
)
×
k
x = x_0\times \frac{c}{gcd(a , b)} + \frac{c}{gcd(a,b)}\times k
x=x0×gcd(a,b)c+gcd(a,b)c×k
其中
k
∈
Z
k\in Z
k∈Z。
具体代码如下:
int exgcd(int n , int m , int &x , int &y)
{
if(m == 0)
{
x = 1;
y = 0;
return n;
}
int gcd = exgcd(m , n % m , y , x);
y -= y * n / m;
return gcd;
}