欧几里得算法求解a*x + b*y =1方程的一组整数解(扩展欧几里德)
1. 欧几里德算法求解最大公约数
1.1 算法过程
欧几里德法又名辗转相除法,可以用于求解两个正整数的最大公约数。他认为,两个正整数的最大公约数等于他们二者中较小的数和较大数与叫较小数取余值的公约数,即,假设有两个正整数 a a a 和 b b b,且 a ≥ b a \ge b a≥b。用 g c d ( a , b ) gcd(a, b) gcd(a,b)表示 a a a和 b b b的最大公约数,则 g c d ( a , b ) = g c d ( b , a % b ) gcd(a, b) = gcd(b, a \% b) gcd(a,b)=gcd(b,a%b) 其中, a % b a \% b a%b 表示 a a a 除 b b b 的余数。
由上述表达式可以发现,欧几里德法将求两个较大值 a a a 和 b b b 的最大公约数的问题转为两个相对较小的值 b b b 和 a a a % b b b 求最大公约数的问题。
令
a
1
=
a
,
b
1
=
b
,
a
2
=
b
1
,
b
2
=
a
1
%
b
1
,
⋯
,
a
n
=
b
n
−
1
,
b
n
=
a
n
−
1
%
b
n
−
1
a_{1}=a,b_{1}=b,a_{2}=b_{1},b_{2}=a_{1} \% b_{1},\cdots ,a_{n}=b_{n-1},b_{n}=a_{n-1} \% b_{n-1}
a1=a,b1=b,a2=b1,b2=a1%b1,⋯,an=bn−1,bn=an−1%bn−1
则
a
1
和
b
1
a_{1} 和b_{1}
a1和b1 的最大公约数
g
c
d
(
a
1
,
b
1
)
=
⋯
=
g
c
d
(
a
n
,
b
n
)
gcd(a_{1},b_{1}) = \cdots = gcd(a_{n},b_{n})
gcd(a1,b1)=⋯=gcd(an,bn)如此递归n次,当传入的两个值中,
a
n
a_{n}
an为
b
n
b_{n}
bn的倍数时,就可以很容易得到,
b
n
b_{n}
bn为二者的最大公约数,同时由于最大公约数相等,可以得出,
a
1
和
b
1
a_{1}和 b_{1}
a1和b1 的最大公约数为
b
n
b_{n}
bn。
1.2 欧几里德法求解最大公约数证明
证明:假设 c c c 为 a a a , b b b 的最大公约数,则 c c c 也一定为 b b b, a a a % b b b 的最大公约数。
需要证明1和2:
-
证明 c c c 为 b b b 和 a % b a \% b a%b 的公约数。
设 c c c 为 a a a 和 b b b 的公约数,则存在正整数 m m m 和 n n n 使得
a = m ⋅ c , b = n ⋅ c (1.1) a=m\cdot c,b=n\cdot c \tag{1.1} a=m⋅c,b=n⋅c(1.1)同时,根据余数的定义,a%b可以表示为 a % b = a − k ⋅ b (1.2) a \% b = a-k\cdot b \tag{1.2} a%b=a−k⋅b(1.2)其中, k k k表示 a a a 除以 b b b 向下取整的倍数。将公式(1.1)代入公式(1.2)可以得到, a % b = c ⋅ ( m + k ⋅ m ) (1.3) a \% b = c \cdot(m+k \cdot m) \tag{1.3} a%b=c⋅(m+k⋅m)(1.3)由此得证c 为a % b 约数,同时 b = n ⋅ c b=n \cdot c b=n⋅c,因此得证 c c c 为 b b b 和 a % b a \% b a%b 的公约数。
-
证明 c c c 为 b b b 和 a a a % b b b 的最大约数。
我们采用反证法证明,我们假设 b b b 和 a a a % b b b 的存在最大公约数 d d d,且 d > c d > c d>c则存在正整数 x 、 y x、y x、y使得 b = x ⋅ d (1.4) b = x\cdot d \tag{1.4} b=x⋅d(1.4) a % b = y ⋅ d (1.5) a \% b=y\cdot d \tag{1.5} a%b=y⋅d(1.5)
将公式(1.4)(1.5)代入公式(1.2)中, a a a可以通过\tag{1.4} x 、 y 、 d x、y、d x、y、d表示为 a = d ⋅ ( y + k ⋅ x ) (1.6) a = d \cdot (y + k \cdot x) \tag{1.6} a=d⋅(y+k⋅x)(1.6)根据公式(1.4)(1.6)可以得到, d 为 a 和 b d为a 和 b d为a和b 的约数,且 d > c d > c d>c,而且在最初的假设条件中 c c c 为 a 和 b a和 b a和b 的最大公约数,因此与且 d > c d > c d>c 矛盾,所以不存在大于 c c c 的值 d d d 为 b b b 和 a a a % b b b 的存在最大公约数,即 c c c 为 b b b 和 a a a % b b b 的最大约数。
1.3 代码(c语言)
在书写代码过程中,当我们得到 a n 为 b n a_{n}为b_{n} an为bn的倍数时,我们会再进行一次辗转相除取余的操作,最后得到 a n + 1 = g c d ( a , b ) , b n + 1 = 0 a_{n+1}=gcd(a,b),b_{n+1}=0 an+1=gcd(a,b),bn+1=0,此时返回a的值即为所求最大公约数
int gcd(int a, int b) {
if (!b) return a;
return gcd(b, a % b);
}
ps:a和b的输入顺序不重要,如果a<b,经过一次函数运行后即会被调整。
2. 欧几里德算法求解 a ∗ x + b ∗ y = 1 a*x + b*y =1 a∗x+b∗y=1方程的一组整数解
2.1 算法思想
扩展欧几里德可以用于求解 a ⋅ x + b ⋅ y = 1 a \cdot x + b\cdot y =1 a⋅x+b⋅y=1的一组整数解,其中 a 、 b 、 x 、 y a、b、x、y a、b、x、y均为整数。
第一部分中介绍了通过欧几里得算法求解最大公约数,他通过将求 a a a 和 b b b 的最大公约数的问题最终转为一个简单的状态,即一个数为另一个数倍数的时候来求解最大公约数,最终返回,这个过程和我们的递归过程类似。
通过欧几里得求解方程的整数解也是类似的,对于该方程,当 a = ± 1 且 b = 0 a= \pm 1且b=0 a=±1且b=0的时候,我们就可以很容易得到方程的解,即 x = ∓ 1 , y x= \mp1,y x=∓1,y为任意值。这就是一个简单的状态。
而通过观察方程可以发现,如果 a a a 和 b b b 存在大于1的公约数,则提取后等式右边会变成一个分数,那么方程将无整数解。因此,只有当系数 a a a 和 b b b 互质,即最大公约数为1时方程才会有整数解。对于两个最大公约数为1的数值,恰巧通过欧几里德法可以不断转换,将两个值转化为1和0,即求解该方程的简单的状态。其中1即为通过欧几里德求得a和b的最大公约数。
2.2 算法原理和过程
假设我们需要求解的是方程为公式:
a
1
⋅
x
1
+
b
1
⋅
y
1
=
1
(2.1)
a_{1}\cdot x_{1}+b_{1}\cdot y_{1} = 1 \tag{2.1}
a1⋅x1+b1⋅y1=1(2.1)通过欧几里德的规则迭代方程系数,令
a
2
=
b
1
,
b
2
=
a
1
%
b
1
=
a
1
−
k
⋅
b
1
(2.2)
a_{2} = b_{1},b_{2} = a_{1} \% b_{1}=a_{1}-k \cdot b_{1} \tag{2.2}
a2=b1,b2=a1%b1=a1−k⋅b1(2.2)可以得到第一个转换后的方程:
a
2
⋅
x
2
+
b
2
⋅
y
2
=
1
(2.3)
a_{2}\cdot x_{2}+b_{2}\cdot y_{2} = 1 \tag{2.3}
a2⋅x2+b2⋅y2=1(2.3)将公式(2.2)代入公式(2.3),可以得到
a
1
⋅
y
2
+
b
1
⋅
(
x
2
−
k
⋅
x
1
)
=
1
(2.4)
a_{1} \cdot y_{2}+b_{1} \cdot (x_{2}-k \cdot x_{1})=1 \tag{2.4}
a1⋅y2+b1⋅(x2−k⋅x1)=1(2.4)其中,
k
k
k表示
a
a
a 除以
b
b
b 向下取整的倍数。
若我们已知转换后的方程(2.3)的解,即已知
x
2
和
y
2
x_{2}和y_{2}
x2和y2的值,对比公式(2.1)和公式(2.4)可以发现,原 方程的解可以由
x
2
y
2
x_{2} y_{2}
x2y2通过如下运算得到:
x
1
=
y
2
,
y
1
=
x
2
−
k
⋅
y
2
(2.5)
x_{1} = y_{2},y1=x_{2}-k \cdot y_{2} \tag{2.5}
x1=y2,y1=x2−k⋅y2(2.5)
以上过程中,我们通过对方程系数进行转变,得到一个新的方程,同时通过新方程的解,又可以推算出原方程的解。
因此我们通过不断重复以上过程,可以将方程系数转变到一个简单的转态,即 a n = 1 , b n = 0 a_{n}=1,b_{n} = 0 an=1,bn=0的时候,此时可以获得第n次转换后的方程的解为,即 x n = 1 , y x_{n}= 1,y xn=1,y为任意值,我们可以令 y = 0 y=0 y=0,并以此为基础不断返回推算出上一个方程解 x n − 1 , y n − 1 x_{n-1},y_{n-1} xn−1,yn−1的值,直到得到待求方程的整数解 x 1 , y 1 x_{1},y_{1} x1,y1的值。
2.3 代码(c语言)
void ex_gcd(int a, int b, int *x, int *y) { //*x和*y用来保存
if (!b) {
*x = 1, *y = 0;
return ;
}
ex_gcd(b, a % b, x, y);
int temp;
temp = *x;
*x = *y;
*y = temp - a / b * (*y);
return ;
}