一、欧几里得算法:
欧几里得算法,也就是数学中的辗转相除法,可以求出两数的最大公因数。
辗转相除法的原理是这样的gcd(a,b)=gcd(b,a%b),
①证明:
第一种证明如下:
设a%b=r;
则a可以表示为a=b*k+r。
对于a,b的任何公因数d有:
d | a 且 d | b;
又∵r=b*k-a;
∴d | r;
∴d也是b,r的公因数
同理,对于b,r的任何公因数f,也有:
f为a,b的公因数
对于a,b和b,r,它们的所有公因数都是一样的
其中,最大公因数也是一样的
∴gcd(a,b)=gcd(b,r)
Q.E.D
第二种证明:
有一个小结论:gcd(a,b)=gcd(a+k*b,b),这个结论的证明较为简单,请读者自己推导。
②算法:
ⅰ)递归:
int gcd(int a,int b)
{
if(b==0) return a;
else return gcd(b,a%b);
}
ⅱ)迭代形式(两者没有本质的区别)
int gcd(int a,int b)
{
int r;
while(b!=0)
r=b,b=a%b,a=r;
return a;
}
二、贝祖(裴蜀)定理:
对于任意整数a,b,一定存在整数x、y,使得a*x+b*y=gcd(a,b);
也就是说,如果a,b互质,就一定存在整数x,y满足a*x+b*y=1
三、拓展欧几里得算法:
①背景:
如果给定贝祖定理中互质的a,b,如何算出x,y呢?
令a>=b;
1.当b=0时:有x=1,y=0。
2.当b≠0时:
设有a*x+b*y=gcd(a,b);
b*x1+(a%b)*y1=gcd(b,a%b);
根据欧几里德原理有:
gcd(a,b)=gcd(b,a mod b);
∴a*x+b*y=b*x1+(a%b)*y1
∴a*x+b*y=b*x1+(a-(a/b)*b)*y1
∴a*x+b*y=a*y1+b*x1-(a/b)*b*y1
根据多项式恒等定理有:
x=y1 且 y=x1-(a/b)*y1
因此,我们得到了x,y的递归式。
②程序实现:
int cd;//cd即为gcd(a,b)
int gcd(int a,int b,int &cd,int &x,int &y)
{
if(b==0)
{
x=1,y=0,cd=a;
return ;
}
gcd(b,a%b,y,x);
y-=x*(a/b);
return ;
}
四、拓展欧几里得算法的应用:
①解不定方程:
对于一个整数不定方程:a*x+b*y=c,如果gcd(a,b) | c,则一定有解。
证明:
∵a|gcd(a,b) , b|gcd(a,b)
∴gcd(a,b) |a*x+b*y;
如果方程成立,则c=a*x+b*y,
∴gcd(a,b) | c
否则方程不成立
如果gcd(a,b) | c,我们怎么用拓展欧几里得算法算出x和y呢?
设p=a/gcd(a,b),q=b/gcd(a,b),r=c/gcd(a,b)。
求出a*x1+b*y1=gcd(a,b)的x1,y1即可,可得x=x1*r,y=y1*r。
对上面新方程进行变形:
a*x1+b*y1=gcd(b,a%b)=b*x2+(a%b)*y2
为了向拓展欧几里得算法靠近,设m=a/b,n=a%b
∴a=m*b+n , n=m*b-a
带入上式,得a*x1+b*y1 = b*x2+(a-(a/b))*y2 = a*y2+b*(x2-(a/b)*y2)
根据多项式恒等定理:
x1=y2,y1=x2-(a/b)*y2
这也正是拓展欧几里得算法中,x,y的变化规律。
继续解不定方程,我们现在已经知道了x,y的一组解(x1*r,y1*r),如何求出其他所有解?
设x1*r=x0,y1*r=y0;
我们已经解出了一组特解:x0,y0,根据通解公式:
x=x0-(b/gcd(a,b))*k,
y=y0+(a/gcd(a,b))*k;(k∈Z)
不定方程就解出来了。
②求逆元
逆元的定义:
背景:
(a+b)%c=(a%c+b%c)%c
(a-b)%c=(a%c-b%c)%c
a*b%c=(a%c*b%c)%c
那么除法呢?
我们知道,一个数除以一个分数等于乘上它的倒数,那么对于模运算呢?
因此,我们规定,如果a*x≡1(mod b),则称x为a的逆元,记为a^(-1)。
则根据定义,(a/b)%c=(a*b^(-1))%c。
那么怎么求逆元呢?事实上,用拓展欧几里得算法算出的x即为a关于b的逆元,具体证明在这里略去。(因为我也不会证,哈哈)