欧几里得及拓展欧几里得算法和应用
http://www.cnblogs.com/keam37/ keam所有 转载请注明出处
一、欧几里得算法:
虽然这是个几乎所有基础书都会写的算法但为了解释拓展欧几里得还是先写下来,并给予证明。
gcd(x,y)为x,y的最大公约数
有gcd(x,y)=gcd(y,x mod y)
证明:
设gcd(x,y)=k;
有 x|k;y|k;
设x mod y=r;即 x=n*y+r;
因为x|k ,则 (n*y+r)|k;
显然 r|k;
证毕。
得到gcd(x,y)=gcd(y,x mod y)后就可以不断迭代最后使 x mod y=0;此时的y即使所求的最大公约数
递归版的代码 如下
1 int gcd(int a,int b) 2 { 3 if(b==0) 4 return a; 5 return 6 gcd(b,a%b); 7 }
非递归
1 int Gcd(int a, int b) 2 { 3 while(b != 0) 4 { 5 int r = b; 6 b = a % b; 7 a = r; 8 } 9 return a; 10 }
二、拓展欧几里得:
既然是在欧几里得算法前加上拓展二字,肯定跟欧几里得里德算法脱不了干系。
讨论这样一个问题:
求方程 ax+by=gcd(a,b)的整数解。
很容易证明这个方程的整数解是存在的
那么现在来讨论如何得到一组解
令
ax1+by1=gcd(a,b);
bx2+(a mod b)y2=gcd(b,a mod b);
由一我们知道gcd(a,b)=gcd(b,a mod b);
则有:
ax1+by1=bx2+(a mod b)y2=bx2+(a–b*(a/b))y2=ay2+bx2-b*(a/b)*by2;(这里a/b 为 a除以b后取整)
由上 可得 x1=y2 y1=x2-(a/b)*y2
从最后a mod b=0 时来考虑临界情况
此时gcd(b,a mod b)=b; 那么x2=1;y2=0;
从此往回迭代 便可以得到x1 和 x2 的一组解
思想是递归的 很容易写出递归的程序
1 int exgcd(int a,int b,int &x,int &y) 2 { 3 if(b==0) 4 { 5 x=1;y=0; 6 return a; 7 } 8 exgcd(b,a%b,x,y); 9 int t=x; 10 x=y; 11 y=t-a/b*y; 12 return 0; 13 }
要得到非递归的程序,那么将上面橙色字标记的公式进行变换
并且令第i个(a/b)=qi ;
可以得到
xn=xn-2-qi*xn-1;yn=yn-2-qi*yn-1;
由于递归的程序调用的次数为O(lgb)所以非递归在这里没有任何优势
因此程序不再赘述。
显然 方程 ax1+by1=gcd(a,b);是有无限多个解的
我们用上述方法求出来的是它的最小整数解
而且可以通过(x+k(b/gcd(a,b)),y-k(a/gcd(a,b)))的方式得到所有的解
三、求解模线性方程:
有方程:
ax≡b(mod n)
等价于 ax’+ny’=b;
要使方程有解 d一定是 由元素a 生成的模n群中的元素;
所以当 gcd(a,n)| b 原方程有解
已经能 用拓展欧几里得算法求得 ax'+by'=gcd(a,b);
由此我们构造
原方程的一个解x0=x'(b/d) mod n;
ax0≡ax'(b/d) (mod n)
≡d(b/d) (mod n)
≡b (mod n)
在求出 ax+ny=gcd(a,n)x的解后
原方程的一个解x0=x*(b/d);
由xi=x0+(n/d)*p(0到d-1)得到
因为由元素a生成的群中 共有 d 个元素,且每个相差d
特别的:当b=1时 即 ax≡1(mod n)时
求的就是a的乘法逆元
参考书目:《算法导论》、《初等数论及其应用》