扩展欧几里德算法解线性方程ax+by=c

问题:ax+by=c,已知a、b、c,求解使该等式成立的一组x,y。其中a、b、c、x、y均为整数

a,b的最大公约数为gcd(a,b)。如果c不是gcd(a,b)的倍数,则该等式无解,因为等式左边除以gcd(a,b)是整数,而等式右边除以gcd(a,b)后为小数。

因此,只有当c是gcd(a,b)的倍数的时候,该等式有解。这样,可以通过计算使ax1+by1=gcd(a,b)成立的x1、y1,然后有x=(c/gcd(a,b))*x1,y=(c/gcd(a,b))*y1,得到x,y。

问题就被转换为求使ax+by=gcd(a,b)成立的一组x,y。这可以用扩展欧几里德算法求解。如下:

如果b为零,则gcd(a,b)=a,那么x=1,y=0为一组解。

如果b不为零,根据欧几里德定理,可以设

ax1+by1=gcd(a,b)=gcd(b,a%b)=bx2+(a%b)y2=bx2+(a-(a/b)*b)y2

化简后有x1=y2,y1=x2-(a/b)y2。因此x1,y1依赖于x2,y2,同理依次类推递归调用求出x3,y3,x4,y4……,类似于辗转相除,直到b=0时,求出xn,yn,便可以推出x1,y1的值。

扩展欧几里德算法:

//  扩展欧几里德算法,解gcd(a, b) = ax + by
//  结果存储在x,y中,用户调用时保证a、b、c都是整数
//  返回a,b的最大公约数
int  extended_euclid( int  a,  int  b,  int   & x,  int   & y)
{
    
if (b  ==   0 //  gcd(a, b) == a
    {
        x 
=   1 ;
        y 
=   0 ;
        
return  a;
    }
    
int  n  =  extended_euclid(b, a % b, x, y);
    
int  tmp  =  x;
    x 
=  y;
    y 
=  tmp  -  static_cast < int > (a / b) * y;
    
return  n;
}

用户调用linear_equation求解线性方程:

//  等式ax+by=c,已知a、b、c,求x和y。
//  解该线性方程等同于解同余式ax = c(mod b)
//  返回值表示是否有解,true有解,false无解
bool  linear_equation( int  a,  int  b,  int  c,  int   & x,  int   & y)
{
    
int  n  =  extended_euclid(a, b, x, y);
    
if (c % n)
        
return   false ;
    
int  k  =  c / n;
    x 
*=  k;
    y 
*=  k;
    
return   true ;
}

linear_equation函数也可以用来解同余式ax=c(mod b)。

由ax=c(mod b),可以得到ax = mb+r;c = nb+r。化简可以得到ax+(n-m)b=c。调用linear_equation可以求出x。

 

 

你可能感兴趣的:(c,算法,存储,扩展)