扩展欧几里得算法是欧几里得算法(又叫辗转相除法)的扩展。已知整数
a,b
,扩展欧几里得算法可以在求得
a,b
的最大公约数(
gcd(a,b)
)的同时,能找到整数
x,y
(其中一个很可能是负数)(贝祖等式告知等式有解),使它们满足 Bézout’s identity(贝祖等式),
d=gcd(a,b)=ax+by
,如果
a,b
互质又可改写为
1=gcd(a,b)=ax+by
,又可用同余的观点改写本式,
ax≡1(modb)
,或者写作
axmodb=1
。比如用来计算
115⋅xmod367=1
中的
x
,因为115与367互质,所以
def ext_euclid(a, b):
if b == 0:
return (a, 1, 0)
d, x, y = ext_euclid(b, a%b)
return (d, y, x-a//b*y)
# 返回三元组
if __name__ == '__main__':
print(ext_euclid(115, 367))
# (1, 150, -47)
扩展欧几里得算法主要有下列应用:
求解不定方程
可见对
c
必须是
def linear_equation(a, b, c):
d, x, y = ext_euclid(a, b)
if c%d:
raise 'no solution'
k = c//d
return d, x*k, y*k
if __name__ == '__main__':
print(linear_equation(6, 8, 4))
# 6x+8y=4
# (2, -2, 2)
# 6与8的最大公约数:8
# x=-2, y=2
求解模线性方程(线性同余方程)
同余方程 ax≡b(modn) (也即 axmodn=b )对于未知数有解,当且仅当 gcd(a,n)|b (也即 bmodgcd(a,n)=0 )。当方程有解时,方程有 gcd(a,b) 个解;
def mod_linear_equation(a, b, n):
# ax === b (mod n)
d, x, y = ext_euclid(a, n)
if b%d:
raise 'no solution'
x0 = x*(b//d)%n
# 特解
# 通解:
# [(x0+i*(n//d))%n for i in range(d)]
return d, x0
我们来看通解的求法,记解之间的间隔为
dx
,则:
也即
n|a⋅dx
,又
a|a⋅dx
,可见
a⋅dx
是
a,n
的公倍数,又
d
是
求解模的逆元
同余方程
ax≡b(modn)
,如果
gcd(a,n)==1
,则方程只有唯一解,在这种情况下,如果
b==1
,同余方程
ax≡1(modn),gcd(a,n)==1
,此时称求得的
x
为
其实对于同余方程
总结
a,n
互质,一定有解;
gcd(a,n)|b
,也有解,否则无解;
References
[1] 扩展欧几里得算法
[2] 算法导论,chap 31 数论算法
[3] 扩展欧几里得算法