欧几里德算法
int Eucild(int a,int b) //欧几里德算法求gcd(a,b) { if(!a) return b; return Eucild(b%a,a); }
扩展欧几里德算法
扩展欧几里德算法是在欧几里德算法的基础上加了一些功能,使其不仅能够求A,B的最大公约数gcd(A,B),而且能求形如Ax+By=gcd(A,B)的x和y的整数解。
为了便于理解扩展欧几里德算法,先来分析一下欧几里德算法求最大公约数的过程,欧几里德算法的递归出口是a为0,当递归到某一层a=0时,b即为最大公约数,不难想到对于此层来说a=0, b=gcd(A,B),对于此时a,b的值来说,直接就能得出如下等式a*0+b*1=gcd(A,B),很显然,对于此层递归a,b的值来说,(0,1)是方程的一组解。
下面的问题是,如果知道了下一层递归的解(x1,y1),怎么得到本曾递归的解(x,y),注意上面欧几里德算法递归调用传的参数,很容易发现,下一层递归中的a1就是本层的b%a,b1是本层的a,知道了下一层a1*x1+b1*y1=gcd(A,B)的解后,我们就可以算出a*x+by=gcd(A,B)的解,过程如下:
设后一层递归得到的解为x1,y1
a1*x1+b1*y1=gcd(A,B)
求本曾递归a*x+b*y=gcd(A,B)的解 (其中a1=b%a,b1=a)
则将a1用b%a替换,b1用a替换则得到如下等式
(b%a)*x1+a*y1=gcd(A,B)
用(b-(b/a)*a)替换b%a得到
(b-(b/a)*a)*x1+a*y1=gcd(A,b)
整理得到
a*(y1-b/a*x1)+b*x1=gcd(A,b)
此时即可得到本曾递归的解 x=(y1-b/a*x1),y=x1
扩展欧几里德算法求解线性方程系数本质上就是一个回代的过程,在下一层递归解的基础上求出本层递归的解,当回溯到a=A,b=B时即得到了Ax+By=gcd(A,B)的解。下面用C++描述一下扩展欧几里德算法。
int Extended_Eucild(int a,int b,int &x,int &y) /*C语言可以用指针*/ { if(!a) { x=0; y=1; /*递归出口的解一定是x=0,y=1*/ return b; } int gcd=Eucild(b%a,a,x,y),t; /*根据下一层递归的解推出本曾递归的解*/ t=x; x=y-b/a*x; y=t; return gcd; }
扩展欧几里德解一次同余方程
下面考虑下这个问题 Ax≡C (mod B) 求整数x
上式存在整数解的充要条件为gcd(A,B)|C,即C是gcd(A,B)的倍数。
求解的过程可以用上面扩展欧几里德算法(废话......),既然我们知道了C一定是gcd(A,B)的倍数,我们不妨先求出使得Ax+By=gcd(A,B)的整数解x,y,然后等式左右乘C/gcd(A,B)后就得到一个解。
上面的方法可以得到一个整数解x,知道一个解后如何得到所有解呢?,很容易看出来,在得到一个解x后,可以在x的基础上任意加减B,得到新的解仍然满足性质。直接加减B有没有可能造成解的遗漏呢?,所以现在问题是,有没有比B更小的数,将其任意加减在x上结果还满足方程?。
假设x是方程一解,即(Ax)%B=C
让我们看一下任意在x上加减B的情况
A*(x+B)%B=(Ax)%B+(AB)%B=C 很显然满足方程
假设在x上加上一个小于等于B的整数B/L(L>=1)后,还满足A*(x+B/L)%B=C,则有
(Ax)%B+(AB/L)%B=C
此时必须保证A是L的倍数,B也是L的倍数,并且L尽可能大,这正是gcd(A,B)的定义,故L=gcd(A,B)
所以我们求出了一个更小的数B/gcd(A,B),得到一组解x后,通过在x上任意加减B/gcd(A,B),从而得到所有满足方程的解,避免了解的遗漏。
下面用C++描述扩展欧几里德解一次同余方程Ax≡C (mod B) 的过程
int x,y,gcd; gcd=Extended_Eucild(A,B,x,y); if(C%gcd==0) { /*存在解*/ x*=C/gcd; /*求出一个解*/ /*在x基础上任意加减B/gcd即得到所有解*/ } else { /*无解*/ }
纯原创