扩展欧几里得算法的目的是为了计算gcd(a,b)=ax+by的一个整数根。
过程:由欧几里得算法,gcd(a,b)=gcd(b,a mod b),可先解出gcd(b,a mod b)=bx'+(a mod b)y'再由x'、y'推出x与y。
那么当b为0时,得出此时方程x=1,y=0。这是边界。
当b不为0时,gcd(b,a mod b)=bx'+(a-[a/b]*b)y'=ay'+b(x'-[a/b]y')——[a/b]为a/b的下取整
则gcd(a,b)=ay'+b(x'-[a/b]y'),则原方程有一根为x=y',y=x'-[a/b]y',只要递归求根即可
综上若gcd(a,b)=ax+by有根x与y,则当b=0时有根x=1且y=0;否则先解出gcd(b,a mod b)=bx'+(a mod b)y',再可得出其一根x=y',y=x'-[a/b]y'。
直接上代码。
#include <iostream>
#include <string.h>
#include <stdio.h>
using namespace std;
int n,m,x,y,n1,m1;
void aa(int t,int s)
{
if (s==0)
{
x=1;y=0;
return;
}
aa(s,t%s);
n1=y;m1=x-t/s*y;
x=n1;y=m1;
return;
}
int main()
{
scanf("%d%d",&n,&m);//n、m即a、b
aa(n,m);
printf("%d %d\n",x,y);
return 0;
}
代码略丑,轻喷。
一个应用:解同余方程整数根
要求同余方程ax≡b(mod n) (n>0)的一个整数根。
方程转换一下,(ax) mod n=b mod n,将b mod n用b'表示,方程便就是b'=ax+ny (y为整数)。不难得知方程当且仅当b'|gcd(a,n)时有解。
则可以用ax'+ny'=gcd(a,n)的根x'、y'各乘以b'/gcd(a,n)便是x、y的值。当然这个可能比较大,还要各对n取一个模便比较合适了。
在此不再贴代码。
另一个运用:乘法逆元
话说为什么叫做乘法逆元,BBG给我们直接上了群论(orzei),但貌似不需要管那么多:
这算是针对于求(a/b) mod k的值的东西,然而当a过大,高精度又没必要,于是可以用求b关于k的乘法逆元b',使得(b*b') mod k=1,
问题就等价于(a*b') mod k
证明:根据b*b'≡1 (mod k)可得b*b'=k*x+1。
b'=(k*x+1)/b。
把b'代入(a*b') mod k=(a*(k*x+1)/b) mod k=[(a*k*x/b) mod k+a/b] mod k=(a/b) mod k。
而 (b*b') mod k=1可以化成kx+1=b*b',其中x与b'为未知数,可以用扩展欧几里得算法求解。
而通过欧几里得算法的性质我们知道,必须要gcd(b,k)=1方程才有解。同理,乘法逆元只在gcd(b,k)=1时存在。