(扩展)欧几里德

来源:互联网 发布:java 调用http请求 编辑:程序博客网 时间:2024/05/26 02:19

        欧几里德算法又称辗转相除法,可以看成是用状态转移来求最大公约数: 设a,b(a>=b,且b!=0),d=gcd(a,b),则d=gcd(b,a%b)。

证明:设r=a%b,既a=b*k+r (k=int(a%b)),故r=a-b*k,r%d=(a-b*k)%d=((a%d)-(b*k)%d+d)%d=0,所以gcd(a,b)=gcd(b,a%b),既求gcd(a,b),转化为求gcd(b,a%b),这就是一个递归的过程了,当gcd(a,b)里的b==0时,递归结束,返回a便是所求结果。

代码如下:

       明白上面以后,扩展欧几里德就容易理解了:已知a,b(a>b)求解一组x,y,使得a*x+b*y=gcd(a,b)=d。

      扩展欧几里德其实就是用于求解上式中的一组x,y,具体过程如下:

      假设当前状态为 a*x1+b*y1=gcd(a,b),下一个状态为b*x2+(a%b)*y2=gcd(b,a%b),现在找两个状态之间的联系 :

因为gcd(a,b)=gcd(b,a%b),所以

a*x1+b*y1=b*x2+(a%b)*y2

                  =b*x2+(a-k*b)*y2,(k=int(a/b))

                  =a*y2+b*(x2-k*y2),

      从而有:x1=y2,y1=x2-k*y2=x2-k*x1。如果你理解了这个过程,就会发现,当前状态中的x1和y1可由它的下一个状态中的x2和y2得到。

 代码如下:

void exgcd(int a,int b,int &d,int &x,int &y){    if (!b) {        x=1,y=0,d=a;//此时a是最开始(a,b)的最大公约数,那么  gcd(a,b)*1+ 0*0=gcd(a,b),肯定对的,在这里,我认为,y可以为任何值都对    }    else {  exgcd(b,a%b,d,y,x); y-=a/b*x;  }}


      应用:

     扩展欧几里得算法的应用基本全都是基于a*x+b*y=d 这个式子来发散的,如求直线上的整数点:

   求直线a*x+b*y+c=0上有多少个整数点满足x1<=x<=x2,y1<=y<=y2。

   由扩展欧几里得算出一组解x1和y1后,设它的另一组解为x2和y2,则a*x1+b*y1=a*x2+b*y2,整理得a*(x1-y1)=b*(y2-y1),令g=gcd(a,b),在方程两边同除于g,并令aa=a/g,bb=b/g,有aa*(x1-y1)=bb*(y2-y1),注意aa和bb互素,所以x1-y1一定是bb的整数倍,设k*b=x1-y1,代入得y2-y1=aa*k。注意前面推导时并没有用到a*x+b*y的左边是什么,所以有如下结论:

      设a,b,c为任意整数,若方程a*x+b*y=c的一组整数解是(x0,y0),则它的任意整数解都可以写成(x0+bb*k,y0-aa*k),其中aa=a/gcd(a,b),bb=b/gcd(a,b),k为任意整数。

     有了这个结论,我们离原题已经很接近了,将原题的a*x+b*y+c=0移项得a*x+b*y=-c,求出一组整数解就行了,那么如何求出一组整数解呢?联系前面可知,当c为g=gcd(a,b)的整数倍是,方程的一组解是(x0*(c/g),y0*(c/g)),(x0,y0是由a*x+b*y=g求得),若c不是g的整数倍,则方程无整数解。



   




0 0