扩展欧几里得算法
先来介绍一下贝祖定理 :
所谓贝祖定理就是说:两个整数a
b
是互质的。等价于ax + by = 1
是有整数解。
贝祖定理另一种更一般的形式,说的是两个整数 a、b有最大公因数是c,等价于方程 ax+by=c有整数解。
即如果a、b是整数,那么一定存在整数x、y使得ax+by=gcd(a,b)
。
换句话说,如果ax+by=m
有解,那么m一定是gcd(a,b)的若干倍。
有一个直接的应用就是 如果ax+by=1
有解,那么gcd(a,b)=1
;
要求出这个最大公因数gcd(a,b),我们最容易想到的就是古老悠久而又相当强大的辗转相除法:
int gcd(int a,int b)
{
return b==0?a:gcd(b,a%b);
}
但是,对于上面的式子ax+by=m
来说,我们并不仅仅想要知道有没有解,而是想要知道在有解的情况下这个解到底是多少。
假设当前我们在求的时a和b的最大公约数,而我们已经求出了下一个状态:b和a%b的最大公因数,并且求出了一组x和y使得 b*x+(a%b)*y=gcd
首先我们知道:a%b=a-(a/b)*b;带入:
b*x1 + (a-(a/b)*b)*y1
= b*x1 + a*y1 – (a/b)*b*y1
= a*y1 + b*(x1 – a/b*y1) = gcd 发现 x = y1 , y = x1 – a/b*y1
这样我们就得到了每两个相邻状态的x和y的转化,就可以在求gcd
的同时对x和y进行求值了
#include<iostream>
using namespace std;
int ex_gcd(int a, int b, int *x, int *y) {
if(!b) {
*x = 1;
*y = 0;
return a; //到达递归边界开始向上一层返回
}
int xx, yy, ret = ex_gcd(b, a % b, &xx, &yy);
*x = yy; //把xx yy变成上一层的
*y = xx - (a / b) * yy;
return ret; //得到a b的最大公因数
}
int main() {
int a, b, c, x, y;
cin >> a >> b;
cout << ex_gcd(a, b, &x, &y) << endl; //a, b最大公约数
cout << a * x + b * y << endl; //判断是否是1
cout << x << ' << y << endl; // 两个解的值:
return 0;
}