扩展欧几里得

来源:互联网 发布:淘宝店怎么登陆千牛 编辑:程序博客网 时间:2024/05/22 00:15

欧几里得也就是辗转相除法是用来求a,b的最大公因数gcd(a,b)的,那么如果d是a,b的最大公因数,那么一点有ax+by=d。如何求解这个二元一次方程,就要用到扩展欧几里得了。

下面先给出程序

int e_gcd(int a,int b,int &x,int &y)//返回最大公因数

{

  if(b==0)

     x=1;y=0;return a;

 int ans=e_gcd(b,a%b,x,y);

 int tmp=x;

 x=y;

 y=tmp-(a/b)*y;//2

 return ans;

}

为什么会有2这个式子呢?

我们从后往前推

最终的状态是x=1,y=0,b=0,a是最大公因数,那么初始状态呢?

我们知道第一次后gcd(a,b)==gcd(b,a%b)的,那么相应的ax+by==bx1+(a%b)y1==bx1+(a-a/b*b)y1

化简一下就是ay1+b(x1-a/b*y1) 那么我们就可以知道,第一次后x变成了y1,y变成了x1-a/b*y1。所以也就有了式子2

另一个问题是我们得到的解x0,y0是一个特解,其通解为x=x0+b/d*t ,y=y0-b/d*t 那么由此我们就可以得到最小的x解(x0%b/d+b/d)%b/d。这里考虑到不使解为负数的情况,所以加了求余函数。

相应的,我们可以求任意的模线性方程ax+by=c。先求出ax+by=gcd(a,b),如果gcd(a,b)是c的因子,方程有解,只需要在原解的情况下*c/gcd(a,b)就好

最小的x解怎么得到的呢?

a*x0+b*y0=gcd(a,b);

如果c%gcd==0  那么此方程有解,否则没有解

若有解

方程两边同时乘以   c/gcd(a,b)  得    (a*c/gcd(a,b))*x0+(b*c/gcd(a,b))*y0=c;

这时得出方程的一个解   x1=x0*c/gcd(a,b)     y1=y0*c/gcd(a,b) 

求最小整数解 意思把x1变到减少到不能减少为止  也就是把x0 减少到不能减少为止

若x0减小x,那么方程左边 整体会减少  (a*c/gcd(a,b))*x   此时 y0 需要增加相应的数使得等式平衡

而假设 y0增加了y  总体增加了  (b*c/gcd(a,b))*y  此时 (a*c/gcd(a,b))*x==(a*c/gcd(a,b))*y

而且x,y为整数  我们可以得到  x/y==b/gcd(a,b)  /   a/gcd(a,b) 

这时  x每次减少 b/gcd(a,b)   y只需增加 a/gcd(a,b)  就可以使得等式平衡。  那为什么我们不约掉gcd(a,b)?

因为x越小,我们得到的最小整数解就会越小。

2 应用:有扩展欧几里德求mod m的逆元

对于整数a,m,如果存在整数b,满足ab=1(mod m)(那个等号是三条线),那么称b是a的模m的乘法逆元。如果b存在,必有gcd(a,m)=1

求解方法可以调用扩展欧几里得

int mod_reverse(int a,int m)

{

int x,y;

int gcd=e_gcd(a,m,x,y);

if(gcd==1)

  if(x<0) x=(x%m+m)%m;

 return x;

else

 return 0;

}



原创粉丝点击