扩展欧几里德

扩展欧几里德:

两个整数a,b,他们的最大公因数是gcd(a,b),那么对于ax+by=gcd(a,b)这样的不定方程,存在若干对(x,y)使得等式成立,而扩展欧几里得可以求出其中的一对特解。

Start:

对于一个欧几里得求最大公因数的过程:

                               比如求  a=12  ,  b=18   的最大公因数 ( 最大公因数是6 ) :

                                                a          b                              x             y

                                         gcd(12    ,   18)

                                     =  gcd(18    ,   12)

                                     =  gcd(12    ,    6  )

                                     =  gcd( 6    ,     0 )                           1             0

 

问题是:求出一对(x,y),使得ax+by=gcd(a,b)成立。

最后一轮辗转相消剩下的两个数是最大公因数和0,然后可以得到这对数的一组特解x=1,y=0,使得等于最大公因数(为什么?非常明显)

然后由底往上回溯,根据[6,0] 的特解(1,0),推出[12,6]的特解,再根据[12,6]的特解推出[18,12]的特解(得到最初想要的结果),以上便是扩展欧几里得的大致过程。

以下便是说明怎么回溯:

                                                                gcd(a,b)   =     ax        +    by

    (辗转相消) 往下递归一步:              gcd(a,b)     =    b(x1)    +    a%b(y1)             (注,x1,x是为了区分,彼此不同)

 

   使用一些小学知识,整理,变形等式:

   (a%b本来就是等于a-a/b*b):              gcd(a,b)     =    b(x1)    +   (a-a/b*b)(y1)

                                                               gcd(a,b)     =    b(x1)    +   a(y1)         -     a/b*b(y1)

                                                               gcd(a,b)     =    a(y1)    -    a/b*b(y1)  +     b (x1)  

                                                               gcd(a,b)    =    a(y1)    +    b(   (x1)   -   a/b(y1)   )

 

观察第一个式子和最后一个式子可知,x=  y1,    y=  (x1)  -   a/b*(y1)   。       (红色)

使用本层特解x1,y1,根据上面那个式子推出上一层特解  x,y,即是回溯过程。

 

演示:

已知最后一层解是:(1,0)

                                                a          b                              x             y

                                         gcd(12    ,   18)

                                     =  gcd(18    ,   12)

                                     =  gcd(12    ,    6  )

                                     =  gcd( 6    ,     0 )                           1             0

 

求往上一层,此时x1=1,y1=0。那么 x=y1=0,    y= (x1)  -   a/b*(y1)  = 1-12/6*0=1  解(0,1):

                                                a          b                              x             y

                                         gcd(12    ,   18)

                                     =  gcd(18    ,   12)

                                     =  gcd(12    ,    6  )                          0             1

                                     =  gcd( 6    ,     0 )                           1             0

 

                   继续:   x1=0,y1=1。那么 x=y1=1,     y= (x1)  -   a/b*(y1)  = 0- 18/12*1=-1,  解(1,-1):

                                                a          b                              x             y

                                         gcd(12    ,   18)

                                     =  gcd(18    ,   12)                           1            -1

                                     =  gcd(12    ,    6  )                          0             1

                                     =  gcd( 6    ,     0 )                           1             0

                  继续:   x1=1,y1=1。那么 x=y1= -1,     y= (x1)  -   a/b*(y1)  = 1- 12 / 18 * -1 = 1,  解(-1,1):

                                                a          b                              x             y

                                         gcd(12    ,   18)                          -1             1

                                     =  gcd(18    ,   12)                           1            -1

                                     =  gcd(12    ,    6  )                          0             1

                                     =  gcd( 6    ,     0 )                           1             0

验证:x=-1,y=1,带入 12x+18y=6=gcd(12,18),正确。

实现代码:

#include<bits/stdc++.h>
using namespace std;
int ex_gcd(int a,int b,int &x,int &y){
	if(b==0){
		x=1,y=0;
		return a;
	}else{
		int x1,y1;
		int gcdab=ex_gcd(b,a%b,x1,y1);
		x=y1;
		y=x1-a/b*y1;
		return gcdab;
	}	
}
int main()
{
	int x,y;
	int gcdab=ex_gcd(12,18,x,y);
	printf("%d,%d,%d\n",x,y,gcdab);
	return 0;
} 

注:以上使用了x1,y1变量只是为了看得清晰点,实际上可以改成不需要的。

通过一组特解求其他解:

ax+by=gcd(a,b),a项和b项同是加,减ab的最小公倍数等式平衡,并可得其他解。

ax+lcm(a,b)+by-lcm(a,b)=gcd(a,b)    ->     a(x+lcm(a,b)/a)+b(y-lcm(a,b)/b)=gcd(a,b)

所以,求得一组特解之后,通过x+lcm(a,b)/a ,y-lcm(a,b)/b ,可得其他解。

其中lcm(a,b)为ab的最小公倍数,lcm(a,b)=ab/gcd(a,b) ,

所以也可以表示为:x+b/gcd(a,b)y - a/gcd(a,b)

求不定方程ax+by=c

扩展欧几里德求得的是a(x1)+b(y1)=gcd(a,b)的特解。而一般来说c是有可能不等于gcd(a,b)的,那么这时两边乘以c/gcd(a,b)就变成ax +  by  =c 的形式了:

a(x1)   *   c/gcd(a,b)   +   b( y1 )   *    c/gcd(a,b)   =    gcd(a,b)   *   c /  gcd(a,b)   =   c

这里应该注意到:c/gcd(a,b)应该为整数,也就是说c  能够被 gcd(a,b)整除。

x=x1*c/gcd(a,b),y=y1*c/gcd(a,b)

其他组的特解表示为:

            求得一组特解x,y   使得ax+by=c成立之后,通过加减gcd(a,b)可以使得 等式仍然成立:ax +gcd(a,b)  +by - gcd(a,b) =c,同时使得x,y的增减之后仍是整数:

x=x+b/gcd(a,b) , y=y+a/gcd(a,b) 

k表示正整数。

求最小正整数的特解:

形如 : x存在着若干个解:x=  x1+k * b/gcd(a,b) 等差数列?同余原理?这样的式子是存在着最小正整数取值的,

令p=b/gcd(a,b)

所以ax+by=c 的  x   的最小正整数解,即是先求出一对特解:x, y.

然后x=   (x%p+p)%p ,(从某个起点不断加p,可以从起点x,p,推断出最小正整数的起点)

 

比如:x=8,p=3,从8开始不断加3,那么最小正起点是(8%3+3)%3= 2  ,

比如:x=-12,p=5,从-12开始不断加5,那么最小正起点是 (-12%5+5)%5= 3   

比如:x=8,p=4   (8%4+4)%4=0 ,那么此时x=0,结果应该是x+p=4

(模p意义下x有可能是0,此时得p),取得最小正整数 x

y= (  c   -  a*x  ) /  b 

 

#include<bits/stdc++.h>
using namespace std;
int ex_gcd(int a,int b,int &x,int &y){
	if(b==0){
		x=1,y=0;
		return a;
	}else{
		int gcdab=ex_gcd(b,a%b,y,x);
		y-=x*a/b;
		return gcdab;
	}	
}
int getMin_x(int a,int b,int c,int &x,int &y){
	int gcdab=ex_gcd(a,b,x,y);
	if(c%gcdab==0){
		x*=c/gcdab;y*=c/gcdab;
		int p=b/gcdab;
		x=(x%p+p)%p;
		if(x==0)x+=p;
		y=(c-a*x)/b;
	} 
}
int main()
{
	int x,y;
	int a=12,b=18,c=36;     //12x+18y=36
	getMin_x(a,b,c,x,y);
	printf("%d,%d\n",x,y);
	return 0;
} 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值