欧几里得算法, 是用来求两数之前的最大公约数的一个算法, 又称辗转相除法.
记: gcd(a,b)为a,b两数的最大公约数
那么有 gcd(a,b) == gcd(b,a%b)
具体证明如下 :
令 a%b = r
那么总会存在一个k使得 a = b*k+r
所以 r = a - b*k;
设 x 为a,b的公约数, 那么 a%x==0&&b%x==0
所以r % x == 0 又因为a%b == r 所以方程式可以改为 (a%b) % x == 0;
所以x又是a%b和b的共同的公约数,
因为x事先没有确定, 所以x可以取任意a与b的公约数,
既然a与b的公约数 和 b与a%b的公约数都相同,
那么 也就是说明 a和b的最大公约数 与 b和a%b的最大公约数相同
因此 gcd( x,y ) == gcd(y,x%y).
以上是欧几里得算法的证明, 代码为:
int gcd(int x,int y){
if(y == 0) return x;
return gcd(y,x%y);
}
有一个定理为 对于任意整数a,b都有 ax+by = gcd(a,b)
我们知道欧几里得算法是可以求出gcd(a,b)的, 但是x,y怎么求呢,
对于任意整数a 和 b 我们有 ax + by = gcd(a,b);
又根据之前的结论知道 gcd(b,a%b) == gcd(a,b).
所以上面方程式可以改为 b * x' + (a%b)* y' = gcd(a,b);
又因为 a%b可以改写为 a - (a/b)*b // a/b向零取整
所以原式可以改写为 b* x' + a* y'- (a/b)*b* y' = gcd(a,b).
此时方程又可以改写成 a* y' + b * ( x' - (a/b)* y') = gcd(a,b).
将上面的式子拿下来进行比较发现
a * y' + b* (x' - (a/b)* y') = gcd(a,b)
a * x + b* y = gcd(a,b)
发现两式子的a,b都重合了, 综上发现一个x和y的值
即 x = y' , y = ( x' - (a/b)* y' ).
这样子, 从 最后求出最大公约数的那一层往前一直回溯, 我们就会得到最终的x和y的值
这个地方有一个边界, 也就是 当 a%b == 0的时候, b* x' = gcd(a,b). x'等于1 y'可以取y' = 0;
下面可以举例
最后改方法用代码来表示
int gcd(int a,int b,int& x,int& y){
if(b == 0){
x = 1;y = 0;
return a;
}
//根据x = y' , y = x' - (a/b)*y';
//首先因为用的是&运算符,先保存上一次的x结果
int c = gcd(b,b%a,x,y);
int tp = x;
x = y; //将x置为 y'.
y = tp - a/b*x;
return c;
}
//以上代码可以简化为
void gcd(int a,int b,int& c,int& x,int &y){ //c为最大公约数
if(b == 0){
x = 1,y = 0;
c = a;
}
gcd(b,a%b,c,y,x);
y = y-a/b*x;
}