欧几里得扩展算法
2010-10-03 11:06
267 查看
[b]欧几里得扩展算法
[/b]
我的理解能力实在欠佳,欧几里德算法老早就已经消化在肚子里了,但是却花了我两天的时间去理解扩展的欧几里德算法。在这里我把自己对扩展欧几里德的想法写在下面,以备不时之需~
首先扩展欧几里德主要是用来与求解线性方程相关的问题,所以我们从一个线性方程开始分析。现在假设这个线性方程为a*x+b*y=m,如果这个线性方程有
解,那么一定有gcd(a,b)
|
m,即a,b的最大公约数能够整除m(m%gcd(a,b)==0)。证明很简单,由于a%gcd(a,b)==b%gcd(a,b)==0,所以
a*x+b*y肯定能够整除gcd(a,b),如果线性方程成立,那么就可以用m代替a*x+b*y,从而得到上面的结论,利用上面的结论就可以用来判断
一个线性方程是否有解。
那么在a*x+b*y=m这个线性方程成立的情况下,如何来求解x和y呢?
1.令a1=a/gcd(a,b),b1=b/gcd(a,b),m1=m/gcd(a,b)。如果我们能够首先求出满足
a*x1+b*y1=gcd(a,b)这个方程的x1和y1,那么x=x1*m1,y=y1*m1就可以求出来了。由欧几里德算法
gcd(a,b)=gcd(b,a%b),所以a*x1+b*y1=gcd(a,b)=gcd(b,a%b)=b*x2+(a%b)*y2,现在只要做一
些变形就可以得到扩展欧几里德算法中的用到的式子了。令k=a/b(商),r=a%b(余数),那么a=k*b+r。所以r=a-k*b,带入上式,得到
a*x1+b*y1=b*x2+(a-(a/b)*b)y2=a*y2+b*(x2-(a/b)*y2)
=>
x1=y2,y1=x2-(a/b)*y2。有了这两个式子我们就知道了在用欧几里德求最大公约数的时候,相应的参数x,y的变化。现在再回过头来看一下
扩展欧几里德算法的代码就很好理解了,实际上扩展欧几里德就是在求a和b的最大公约数的同时,也将满足方程a*x1+b*y1=gcd(a,b)的一组
x1和y1的值求了出来。下面代码中突出的部分就是标准的欧几里德算法的代码。
__int64 exGcd(__int64 a,__int64 b,__int64
&x,__int64 &y){
if(b==0){
x=1;
y=0;
return a;
}
__int64
g=exGcd(b,a%b,x,y);
__int64
temp=x;
x=y;
y=temp-(a/b)*y;
return
g;
}
2.那么x,y的一组解就是x1*m1,y1*m1,但是由于满足方程的解无穷多个,在实际的解题中一般都会去求解x或是y的最小正数的值。以求x为例,
又该如何求解呢?还是从方程入手,现在的x,y已经满足a*x+b*y=m,那么a*(x+n*b)+b*(y-n*a)=m显然也是成立的。可以得出
x+n*b(n=…,-2,-1,0,1,2,…)就是方程的所有x解的集合,由于每一个x都肯定有一个y和其对应,所以在求解x的时候可以不考虑y的取
值。取k使得x+k*b>0,x的最小正数值就应该是(x+k*b)%b,但是这个值真的是最小的吗??如果我们将方程最有两边同时除以
gcd(a,b),则方程变为a1*x+b1*y=m1,同上面的分析可知,此时的最小值应该为(x+k*b1)%b1,由于b1<=b,所以这个
值一定会小于等于之前的值。在实际的求解过程中一般都是用while(x<0)x+=b1来使得为正的条件满足,为了更快的退出循环,可以将b1改
为b(b是b1的倍数),并将b乘以一个倍数后再加到x上。
PS:在求x的最小正数的时候采用while(x<0)x+=b在时间上有的时候是很不理想的,有其实x,b都很小的情况下。
实际上只要用通过x=(x%b1+b1)%b1就可以了,因为负数取余相当于正数取余再加个负号
[/b]
我的理解能力实在欠佳,欧几里德算法老早就已经消化在肚子里了,但是却花了我两天的时间去理解扩展的欧几里德算法。在这里我把自己对扩展欧几里德的想法写在下面,以备不时之需~
首先扩展欧几里德主要是用来与求解线性方程相关的问题,所以我们从一个线性方程开始分析。现在假设这个线性方程为a*x+b*y=m,如果这个线性方程有
解,那么一定有gcd(a,b)
|
m,即a,b的最大公约数能够整除m(m%gcd(a,b)==0)。证明很简单,由于a%gcd(a,b)==b%gcd(a,b)==0,所以
a*x+b*y肯定能够整除gcd(a,b),如果线性方程成立,那么就可以用m代替a*x+b*y,从而得到上面的结论,利用上面的结论就可以用来判断
一个线性方程是否有解。
那么在a*x+b*y=m这个线性方程成立的情况下,如何来求解x和y呢?
1.令a1=a/gcd(a,b),b1=b/gcd(a,b),m1=m/gcd(a,b)。如果我们能够首先求出满足
a*x1+b*y1=gcd(a,b)这个方程的x1和y1,那么x=x1*m1,y=y1*m1就可以求出来了。由欧几里德算法
gcd(a,b)=gcd(b,a%b),所以a*x1+b*y1=gcd(a,b)=gcd(b,a%b)=b*x2+(a%b)*y2,现在只要做一
些变形就可以得到扩展欧几里德算法中的用到的式子了。令k=a/b(商),r=a%b(余数),那么a=k*b+r。所以r=a-k*b,带入上式,得到
a*x1+b*y1=b*x2+(a-(a/b)*b)y2=a*y2+b*(x2-(a/b)*y2)
=>
x1=y2,y1=x2-(a/b)*y2。有了这两个式子我们就知道了在用欧几里德求最大公约数的时候,相应的参数x,y的变化。现在再回过头来看一下
扩展欧几里德算法的代码就很好理解了,实际上扩展欧几里德就是在求a和b的最大公约数的同时,也将满足方程a*x1+b*y1=gcd(a,b)的一组
x1和y1的值求了出来。下面代码中突出的部分就是标准的欧几里德算法的代码。
__int64 exGcd(__int64 a,__int64 b,__int64
&x,__int64 &y){
if(b==0){
x=1;
y=0;
return a;
}
__int64
g=exGcd(b,a%b,x,y);
__int64
temp=x;
x=y;
y=temp-(a/b)*y;
return
g;
}
2.那么x,y的一组解就是x1*m1,y1*m1,但是由于满足方程的解无穷多个,在实际的解题中一般都会去求解x或是y的最小正数的值。以求x为例,
又该如何求解呢?还是从方程入手,现在的x,y已经满足a*x+b*y=m,那么a*(x+n*b)+b*(y-n*a)=m显然也是成立的。可以得出
x+n*b(n=…,-2,-1,0,1,2,…)就是方程的所有x解的集合,由于每一个x都肯定有一个y和其对应,所以在求解x的时候可以不考虑y的取
值。取k使得x+k*b>0,x的最小正数值就应该是(x+k*b)%b,但是这个值真的是最小的吗??如果我们将方程最有两边同时除以
gcd(a,b),则方程变为a1*x+b1*y=m1,同上面的分析可知,此时的最小值应该为(x+k*b1)%b1,由于b1<=b,所以这个
值一定会小于等于之前的值。在实际的求解过程中一般都是用while(x<0)x+=b1来使得为正的条件满足,为了更快的退出循环,可以将b1改
为b(b是b1的倍数),并将b乘以一个倍数后再加到x上。
PS:在求x的最小正数的时候采用while(x<0)x+=b在时间上有的时候是很不理想的,有其实x,b都很小的情况下。
实际上只要用通过x=(x%b1+b1)%b1就可以了,因为负数取余相当于正数取余再加个负号
相关文章推荐
- poj 1061 小白算法练习 数论 扩展欧几里得 青蛙的约会
- 欧几里得扩展算法
- 扩展欧几里得(Extended Euclid)算法求最大公约数和乘法逆元
- [数论]HOJ 2185 Min Chain 扩展欧几里得算法
- 欧几里得扩展算法详解及POJ1061
- 欧几里得扩展算法
- [省选前题目整理][SGU 261]Discrete Roots(扩展欧几里得+中国剩余定理+原根+大步小步算法)
- 欧几里得扩展算法
- 扩展欧几里得 小白算法学习
- 欧几里得及欧几里得扩展算法
- 扩展欧几里得算法
- 欧几里得算法和扩展欧几里得算法
- 关于欧几里得及其扩展算法(C语言实现)
- 扩展欧几里得算法理解
- 欧几里得扩展算法
- 欧几里得(Euclid)算法及其扩展
- Java实现算法导论中求解模线性方程解(基于最大公约数欧几里得扩展算法)
- 欧几里得扩展算法
- 算法-扩展欧几里得
- 欧几里得扩展算法