扩展欧几里德算法是用来在已知a, b求解一组x,y,使它们满足贝祖等式: ax+by = gcd(a, b) =d(解一定存在,根据数论中的相关定理)。
扩展欧几里德常用在求解模线性方程及方程组中。
首先,证明一下gcd(a,b)==gcd(b,a%b)
设gcd(a,b) = k
a = n1 * k
b = n2 * k
a%b = (n1%n2)*k
b = n2 * k
现在只需证n2 和 n1%n2 没有公因子
假设有公因子,为r
n2 = num2 * r
n1%n2 = num1 * r
n1 = k*n2 + num1*r
n1 = (k*num2+num1)*r
n1和n2有公因子,这与设gcd(a,b) = k矛盾,因为如果n1和n2有公因子,那么gcd(a,b)=k*r
所以gcd(b,a%b) = gcd (a,b)
(以上证明出处)
由上面的等式,我们可得:
∵gcd(a,b)==gcd(b,a%b)
∴a*x1+b*y1==b*x2+(a%b)*y2 //一定有整数解x,y
∵在计算机科学里a%b的实际运算是 a-(a/b)*b //a/b因为都是整形变量,所以计算时a/b==⌊a/b⌋
∴a*x1+b*y1==b*x2+(a-(a/b)*b)*y2
整理可得a*x1+b*y1==a*y2+b*(x2-(a/b)*y2)
即x1=y2,y1=x2-(a/b)*y2
显然,我们只要找到递归边界,就可以不断求解,直到得出答案
辗转相除法:
int
gcd(
int
a,
int
b)
{
return
b==0?a:gcd(b,a%b);
}
void gcd(int a,int b,int &x,int &y)
{
if (b==0){x=1,y=0;return;}
gcd(b,a%b,y,x); //注意x,y的位置
y-=a/b*x;
}
struct ans
{
int x,y;
};
ans gcd(int a,int b)
{
ans myans,t;
if(b==0){myans.x=1,myans.y=0;return myans;}
t=gcd(b,a%b);
myans.x=t.y;
myans.y=t.x-a/b*t.y;
return myans;
}
可以试一下改变递归边界中的y的值,会有惊喜;
我们得出了一组解 x,y
显然a*x0+b*y0==a*x+b*y //x0,y0为已得解,x,y为其他答案
x=x0+k*b,y=y0-k*a //k为整数,其实你将x,y带入原式,就会发现显然成立