扩展欧几里得算法

来源:互联网 发布:linux suspend resume 编辑:程序博客网 时间:2024/06/18 16:28

扩展欧几里得

扩展欧几里得算法,是使用与如下问题的一种复杂度为log(n)级别的算法:
求ax+by=gcd(a,b)的整数解。
首先,求解这个方程,其实只需要求出一组可行解,其他的解都是可以用这一组可行解推出来的,假设我们已经求得一组可行解x0,y0,那么对于任意的整数k, x0+k*b/(a,b),y0+k*a/(a,b)都是这个方程的一组解。
我们知道,gcd(x,y)=gcd(y,x mod y)(欧几里得算法),
这样,我们可以将问题转化为求方程bX+(a mod b)Y=gcd(a,b)的整数解,先来考虑边界,显然,当b=0时,x=1,y=0就是一组可行解,接下来就需要找出转化后的方程的解X,Y与原方程的解x,y的关系,联立方程:
**ax+by=bX+(a mod b)Y
因为a mod b=a-(a/b)*b,”/”为整除,所以,
ax+by=bX+aY-(a/b)*bY;移项,
a(x-Y)=b(X-(a/b)*Y-y);
所以,x=Y,y=X-(a/b)Y 是原方程的一组解。
代码如下:

void exgcd(int a,int b,int &x,int &y){    if(!b){        x=1;y=0;return;    }    int X,Y;    exgcd(b,a%b,X,Y);    x=Y;y=X-(a/b)*Y;}

这个算法的时间复杂度如何估算呢,和欧几里得算法一样,每次mod最坏可以看成是/2,所以复杂度就是O(logn)的。

有时,扩欧会用来求解逆元:
什么是逆元?
逆元在求形如(a/b)mod m的时候非常有用,由于a/b可能是一个很大的数,直接求出来再mod显然不可行,写高精度有没有必要或是复杂度承受不了,就可以利用逆元把除法转化成乘法。我们定义b在模m的逆元为使bc mod m=1的最小正整数,这样的数有什么用呢?
(a/b)mod m*bc=(a/b*b*c)mod m=(a*c)mod m,由于bc mod m=1,所以这样的乘法并不会改变答案,而乘法的mod运算时满足分布mod的,这样就没有必要去写高精度了。下面我们来看如何求逆元:
得bc mod m=1,所以bc+my=1;
显然,只有当bm互质时,这个方程才有解,也就是说,逆元是有条件的,即bm需要互质,接下来,由于bm互质,那么gcd(b,m)就等于1,就可以用扩欧来求解这个问题了。

扩欧还可以用来求解如下方程:
ax+by=m,
显然,对于这样的方程,只有当gcd(a,b)是m的因子时,方程才有解,因为如果gcd(a,b)不是m的因子,那么等号的左边一定是gcd(a,b)的倍数,而右边又不是,所以方程一定无解,这样,我们可以将问题归化为求方程a/(a,b)*x+b/(a,b)*y=m/(a,b)的解,这样,设p=a/(a,b),q=b/(a,b),那么p与q互质,所以,就可以先求出方程px+qy=1的解,再将x和y分别乘m/(a,b),就是原方程的一组可行解了。

2 0
原创粉丝点击