扩展欧几里得的推导与代码实现
引言 : 裴蜀定理(定义摘自oi wiki)
定义:
设整数a,b是不全为0的整数,则存在整数x,y,使得 ax+by = gcd(a,b)
证明:
1.若a,b有一个数为0,则x取1即可成立
2.若a,b都为正整数,gcd(a,b) 为a,b的共同因子
所以 a%gcd(a,b) = b%gcd(a,b) = 0
由(m+n)%p = m%p+n%p
可以得出 (ax+by)%gcd(a,b) = ax%gcd(a,b)+by%(gcd,a,b) = 0+0 = 0 得证
回到今天的主角扩展欧几里得算法(部分借鉴知乎用户忘忧北萱草的文章)
传统欧几里得算法是用辗转相除算出a,b的最大公约数
扩展欧几里得则是可以在既算出最大公约数的同时,算出ax+by = gcd(a,b) 中的(x,y)
在欧几里得算法中,递归根据的是gcd(a,b) = (b,a%b) = (b,a-b[a/b]) 在扩欧里也会用到这个结论
设两组解(x,y) , (x1,y1) 根据裴蜀定理可得ax+by = gcd(a,b) bx1+(a-b[a/b])y1 = (b,a-b[a/b])
由于(a,b) = (b,a-b[a/b]) 则将两个式子联立求解得 a(x-y1) + b(y-(x1-y1[a/b])) = 0
我们希望这个式子对于所有解集(x,y) 都成立 于是有 x = y1 y = x1-y1[a/b]
此时求解(x,y)已经变成了求解(x1,y1),继续递归直到求解完成。递归结束条件为b=0,此时x=1,y=0
代码实现:
int exgcd(int a, int b, int& x, int& y) //返回的是gcd(a,b) x,y要传引用
{
if(a < b) return exgcd(b, a, y, x);
if(b == 0) //递归的结束条件是 b==0
{
x = 1; y = 0;
return a;
}
else
{
int x1;
int d = exgcd(b, a % b, x1, x); //exgcd(a,b,x,y) 的实质是一位置乘三位置 + 二位置*四位置 = gcd(一位置,二位置)
y = x1 - a / b * x; //根据前文第三处黑体字可知 递归函数的三位置应该是x1,四位置应该是y1
return d; //因为x=y1 所以四位置是x
}
}