我们要学习扩展欧几里得算法首先必须知道什么是欧几里得算法 然后再去理解扩展欧几里得
一、什么是欧几里得算法
其实欧几里得算法我们很熟悉只不过我们并不知道它还有这样一个名字 很简单 其实它就是我们平时所说的辗转相除法求最大公因数 这下就在熟悉不过了吧(不知道什么是辗转相除法!!! 没办法 去找度娘吧)
其计算原理依赖于下面的定理:
定理:两个整数的最大公约数等于其中较小的那个数和两数相除余数的最大公约数
最大公约数(greatest common divisor)缩写为gcd
gcd(a,b) = gcd(b,a mod b) (不妨设a>b且r=a mod b ,r不为0)
其实这也是很好证明的
假设 a=kb+r ----> r=a%b
假设 d是 a,b的一个公因数 即
a/d 是整数 ------->(kb+r)/d也是整数-------> ((kb)/d+r/d)是整数-------->(kb)/d是整数,r/d也是整数
所以 d也是 b 和 r 的公因数
反过来 假设 d是 b , r 的一个公因数 即
(kb)/d+r/d 是整数------->(kb+r)/d是整数------->a/d也是整数
所以 d 也是 a和 b 的公因数
这样我们就得知 a和b的公因数==b和r的公因数 当然最大公因数也是如此 用数学表达式可表示为
gcd(a,b) =gcd(b,a%b)
代码实现:
- int gcd(int a,int b){
- if (b==0)
- return a;
- return gcd(b,a%b);
- }
int gcd(int a,int b){
if (b==0)
return a;
return gcd(b,a%b);
}
二、什么是扩展欧几里得算法
那什么是扩展欧几里得呢 顾名思义它是对欧几里得算法的扩展 其中扩展欧几里得的定义如下:
对于不完全为 0的非负整数 a,b,gcd(a,b)表示 a,b 的最大公约数,必然存在整数对 x,y,使得
gcd(a,b)=ax+by
那我们就明白了 扩展欧几里得是用来求两元一次方程的解的
当然两元一次方程是一个不定方程 它有多组解 但是只要我们求得了它的一组特解我们便可以表示出它的通解
假设方程ax+by=gcd(a,b)一组特解为 X0和Y0那它的通解为
X =X0 + (b/gcd) * t
Y = Y0 - (a/gcd) * t
为什么是通解呢把它们带入方程就会一目了然不再解释
然后我们关心的就是怎么求的它的特解 X0和Y0
我们注意到欧几里得算法执行的最终情况是 b==0, a = gcd
代回原先的方程 x+by=gcd 也就表示为 a * 1 + 0 * y = gcd
在最终状态时我们可以求得方程的解 x=1, y为任意值(默认为0) 但是我们想要的是最初方程的解
那么我们怎样才能从最终方程的解得到最初方程的解呢接下来我们就进行一番推理
假设 ax + by = gcd 是我们最初要求解的方程
但是我们现在却知道了它下一个状态 bx + (a%b)y =gcd的一组通解X0和Y0
因为 a%b = a - (a/b)*b (式中的 "/"为整除)
所以 b*x0 + (a-(a/b)*b)*y0 = gcd (式中的 "/"为整除)
所以 b*x0 + a*y0 -(a/b)*b*y0 = gcd (式中的 "/"为整除)
所以 a*y0 + b*(x0-(a/b)*y0)= gcd
ok了推理完成还没看出来!!!!好吧那我们把推理最后的方程和我们最初要求解的方程比较一下这下发现了吧很容易得到
x = y0
y = x0-(a/b)*y0
代码实现:
- int gcd(int a,intb,int &x,int &y){
- if (b==0){
- x=1;
- y=0;
- return a;
- }
- int ans=gcd(b,a%b,y,x);
- y-=(a/b)*y;
- return ans;
- }