序言:
当博主第一次见到欧几里德算法时,我是不屑一顾的,由于模板比较好背,所以也没有仔细研究过其中的数学原理.这段时间突然喜欢上了数学,碰巧同学讲了一下基础数论,就去听了一听. 由于博主数学基础和学习能力都比较差,没有立即消化其中的知识,于是研究了好几天,直到今天才有所进展,通过这篇博客希望大家能够认识到数学的精妙之处.
正文:
欧几里德算法的推导与证明:
众所周知,欧几里德算法的定理可以表示为:
gcd(a,b)=gcd(b,a%b)gcd(a,b)=gcd(b,a%b)
但是这个定理是如何推导出来的呢?
首先我们可以假设a=k∗b+ra=k∗b+r(其中的r代表着a/b的余数,也就是a%b的结果)
1.首先我们假设d是a和b的最大公约数,则我们可以知道 a可以整除d,表示为a|b,b也可以整除d,表示为b|d,由于r=a−k∗br=a−k∗b 其中a是d的倍数,而且b也是d的倍数,那我们可以得到其实r也是d的倍数,换句话说r也是可以整除d.
2.接下来我们假设d是b和r的最大公约数,则我们可以知道b可以整除d,表示为b|d,r也可以整除d,表示为r|d,由于a=k∗b+ra=k∗b+r其中b是d的倍数,而且r也是d的倍数,那我们可以得知其实a也是d的倍数,换句话说a也是可以整除d.
通过以上的充分必要式的证明方法,我们可以得到:gcd(a,b)=gcd(b,a%b)gcd(a,b)=gcd(b,a%b)
接下来我们来看代码实现(递归) :
int gcd(int a, int b)
{
if(b==0)
return a;
else
return gcd(b,a%b);
}
看起来十分简单,实则暗藏玄机…
首先我们需要考虑当 b=0b=0 时,为何要返回a呢.. 在解释之前,我要说明一点,只有当a > b时 算法才算正式开始进行运算,这是为什么呢?我们举个简单的例子,当 a=12,b=16a=12,b=16 时,我们在第二轮的时候惊奇的发现他递归的却是 gcd(16,12)gcd(16,12) ,这其实算是一种维护的过程,感叹第一写出这份代码人心思的缜密….回归正题,当我们发现 b=0b=0 时,也就是说上一轮的 a%b=0a%b=0 也就是说上一轮的a可以完全整除b,此轮的a则是上一轮的b提供的,所以将b返回即可。
我遇到的问题
在学习欧几里得的时候,我有一个疑惑,在我们刚才的推导过程:假设d是a和b的最大公约数,我们可以推导出 r (a%ba%b)也可以整除d , 既然a,b,r都可以整除d,为什么我们的等式只能写作 gcd(a,b)=gcd(b,a%b)gcd(a,b)=gcd(b,a%b) 而不能写作 gcd(a,b)=gcd(a,a%b)gcd(a,b)=gcd(a,a%b) 呢? 在这个问题上,我思考了很久,终于得到了一定的理解… 首先我刚才说过 只有当 a>ba>b 的时候,算法才开始进行运算,所以说a在这里面是相对是最大的,b其次,而r是最小的…. 我说的可能太过绝对,以下为他们的具体关系:
a≥b≥ra≥b≥r
在我们每轮递归的过程中,希望值是越来越小的…其中a确永远是最大的…而且递归a也是没有意义的…因为我们最终要求的是最大公约数解.
扩展欧几里德算法的解释说明:
在学习完上面所讲的欧几里德算法之后,本节我们来讲一下 扩展欧几里得算法,欧几里德算法是用来做什么的呢?
扩展欧几里德算法是用来在已知a, b求解一组x,y,使它们满足贝祖等式: ax+by=gcd(a,b)ax+by=gcd(a,b),然后再求出现实所所需要的通解。由于证明这个等式成立的过程涉及到其他的数论知识,在学习基础的我们可以暂时把证明过程放在一边,权当这是成立的。
我们已知 a∗x1+b∗y1=gcd(a,b)a∗x1+b∗y1=gcd(a,b) 根据欧几里德,我们可以得到:
gcd(a,b)=gcd(b,a%b)gcd(a,b)=gcd(b,a%b)
gcd(b,a%b)=b∗x2+(a%b)∗y2=b∗x2+(a−floor(a/b)∗b)∗y2gcd(b,a%b)=b∗x2+(a%b)∗y2=b∗x2+(a−floor(a/b)∗b)∗y2
我们最终可以得到:
y1=x2−floor(a/b)∗y2,x1=y2y1=x2−floor(a/b)∗y2,x1=y2
接下来我们来看代码实现(递归) :
int exGcd(int a,int b,int &x,int &y)
{
if(b==0)
{
x=1;y=0;
return a;
}
int r=exGcd(b,a%b,x,y);
int t=x;
y=t-a/b*y;
return r;
}
现在我们考虑一下递归的终点…..当 b=0b=0 我们为何要 x=1x=1 ,y=0y=0 呢…
首先我们知道贝祖等式 a∗x+b∗y=gcd(a,b)a∗x+b∗y=gcd(a,b) 其中a≥gcd(a,b)a≥gcd(a,b) 当 b=0b=0 时 x=1x=1是必然的,满足最终a=gcd(a,b)a=gcd(a,b),而y的取值..由于 b=0b=0 所以y可以取任何值…但是我们最终要求的最小解..所以将其赋值为零…
通过以上的运算过程….我们把a∗x+b∗y=gcd(a,b)a∗x+b∗y=gcd(a,b)的其中一组解解出来了, 仅仅是其中一组解。对于已经得到的解x1, y1,我们便可以求出通解。
通解计算公式:
我需要讲的最后一个问题:
求任何数字n在一定周期t中最小正整数:
int ans = ((n % t)+t) % t;
有关题目:POJ 1601