扩展欧几里得算法

给定两个正整数m和n,我们计算它们的最大公因子d和两个整数a和b,使得a*m+b*n=d

算法流程

  E1.置a'=b=1;a=b'=0;c=m,d=n;

  E2.计算d和r,使得c=q*d+r;

  E3.若r==0;则退出,当前已有a*m+b*n=d;

  E4;c=d;d=r;t=a';a'=a;a=t-q*a;t=b';b'=b;b=t-q*b;返回E2.

证明

 递归版本:

  对于已有的m和n,假设m>n;如果刨除变量a,b,a',b';算法与欧几里得算法完全一样,为计算最大公约数的算法.

  最终要求的为a*m+b*n=d=GCD(m,n);如果改式子成立由欧几里得算法可推出a'*n+b'*(m%n)=GCD(n,m%n);

  因为GCD(m,n)=GCD(n,m%n);

  所以a*m+b*n=a'*n+b'*(m%n)

        =a'*n+b'*(m-(m/n)*n)

        =a'*n+b'*m-b'*(m/n)*n

        =b'*m+(a'-b'*(m/n))*n

  所以a=b';b=a'-b'*(m/n);

  可以推出根据a‘、b'可以计算a、b。

  非递归版本:

  设m为r[0],n=r[-1];根据欧几里得算法可推出

  r[i-2]=r[i-1]*q[i]+r[i]; r=1...n+1;         (1)

  r[i](r=1...n+1)为每次迭代的余数,可知r[n+1]=0;且r[n]=GCD(m,n);

  由于每个r都是前两个r的组合,所以对于a*m+b*n=GCD(m,n)存在(可用数学归纳法证明):

  a[i]*m+b[i]*n=r[i];              (2)

  当i==1时,根据(1)(2)式

    a[1]*m+b[1]*n=r[1]

          =r[-1]-r[0]*q[1]

          =n-q[1]*m

  可推出:a[1]=-q[1],b[1]=1;

  当i==2时,根据(1)(2)式

    a[2]*m+b[2]*n=r[2]

          =r[0]-r[1]*q[2]

          =r[0]-(a[1]*m+b[1]*n)*q[2]

          =m-a[1]*q[2]*m-b[1]*q[2]*n

          =(1-a[1]*q[2])*m-b[1]*q[2]*n

  可推出:a[2]=1-a[1]*q[2],b[2]=-b[1]*q[2];

  当i>=3时,根据(1)(2)式

    a[i]*m+b[i]*n=r[i]

          =-q[i](a[i-1]*m+b[i-1]*n)+(a[i-2]*m+b[i-2]*n)

          =(-q[i]*a[i-1]+a[i-2])*m+(-q[i]*b[i-1]+b[i-2])*n

  对于i>=3,a[i]=-q[i]*a[i-1]+a[i-2],b[i]=-q[i]*b[i-1]+b[i-2];

  当我们定义:a[-1]=0,a[0]=1,b[-1]=1,b[0]=0时,可构造出a,b的公式

    a[-1]=0,a[0]=1,a[i]=-q[i]*a[i-1]+a[i-2](i>=1)

    b[-1]=1,b[0]=0,b[i]=-q[i]*b[i-1]+b[i-2](i>=1)

代码实现

void EGCD(int m,int n)
{
    int a,a1,b,b1,c,d,q,r,t;
    a1=b=1,a=b1=0,c=m,d=n;
    while(1)
    {
        q=c/d,r=c%d;
        if(r==0)
        {
            printf("(%d)*%d+(%d)*%d=%d\n",a,m,b,n,d);
            return;
        }
        c=d,d=r,t=a1,a1=a,a=t-q*a,t=b1,b1=b,b=t-q*b;
    }
}
View Code

 

你可能感兴趣的:(算法)