一、简单介绍
定理:若a和b为正整数,则存在x和y是的gcd(a,b)=ax+by;
换句话说gcd(a,b)可以表示为a、b的整数线性组合。
eg:
gcd(6,14) = (-2)*6+1*14 = 2
已知整数a、b,扩展欧几里得算法可以在求解gcd的同时确定其系数。
首先,我们先模拟下欧几里得求解不定方程的过程
方程:
252*x+198*y=18 // 18是gcd(252, 198)
以下g代表gcd(252, 198)
(1) 252=1*198 + 54
(2) 198=3*54+36
(3) 54=1*36+18
(4) 36=2*18
(3)式表示18可以表示为54和36的线性组合,即18=54-1*36
(2)式表示36=198-3*54,结合上面得18=54-1*(54-1*36)=54-1*(198-3*54)=4*54-1*198
(1)式表示54=252-1*198,结合上面得18=4*(252-1*198)-1*198=4*252-5*198
至此问题得到解决x=4,y=-5
二、递归推导
1、找到递归的出口
可以轻易得出算法的停止状态是:a=gcd,b=0,此时x=1, y=0
2、递归关系
一般情况下
a*x1+b*y1=gcd(a,b)
b*x2+(a%b)y2=gcd(b, a%b)
根据欧几里得我们知道
gcd(a,b)=gcd(b,a%b)
即
a*x1+b*y1=b*x2+(a%b)y2
而
a%b=a-[a/b]*b
所以
a*x1+b*y1=b*x2+(a-[a/b]*b)*y2
展开得到合并(关于a,b的方程)
a*x1+b*y1=a*y2+(x2-[a/b]*y2)*b
根据恒等定理得
x1=y2
y1=x2-[a/b]*y2
三、java实现
由上面我们翻译成java代码可得到
/**
* 扩展欧几里得算法:递归计算xa+yb=gcd(a,b)
* @param a
* @param b
* @param r x=r[0], y=r[1]
* @return gcd(a,b)
*/
public static int extendGcd(int a, int b, int[] r) {
if (b == 0) {
r[0] = 1; r[1] = 0;
return a;
} else {
int gcd = extendGcd(b, a%b, r);
int t = r[0];
r[0] = r[1];
r[1] = t-(a/b)*r[1];
return gcd;
}
}
四、通解
以上计算已经求出的是不定方程的一组解,x和y肯定一个为正一个为负。那么如何得出一组x必为正的解呢,这个也很好得到,假设上面求出的通解是x0,y0,那么就可以x0,y0来表示整个方程的通解:
x=x0+(b/gcd)*t
y=y0-(a/gcd)*t
验证
a*x+b*y =(a*x0+a*b/gcd*t)+(b*y0-b*a/gcd*t)
=a*x0+b*y0=gcd
因为b/gcd与a/gcd互质,所以以上能表示所有通解
举例:
取a=17,b=3120,通过计算得到x0=-367,y0=2,gcd=1,
x=-367+3120*t
y=2-17*t
要使得x>0,t取1
x=-367+3120*1=2753
y=2-17*1=-15