欧几里得算法的推导与证明 || 扩展欧几里德算法的解释说明

序言:

     当博主第一次见到欧几里德算法时,我是不屑一顾的,由于模板比较好背,所以也没有仔细研究过其中的数学原理.这段时间突然喜欢上了数学,碰巧同学讲了一下基础数论,就去听了一听. 由于博主数学基础和学习能力都比较差,没有立即消化其中的知识,于是研究了好几天,直到今天才有所进展,通过这篇博客希望大家能够认识到数学的精妙之处.

正文:

欧几里德算法的推导与证明:

     众所周知,欧几里德算法的定理可以表示为:
                                                      gcd(a,b)=gcd(b,a%b)gcd(a,b)=gcd(b,a%b)
     但是这个定理是如何推导出来的呢?

首先我们可以假设a=kb+ra=k∗b+r(其中的r代表着a/b的余数,也就是a%b的结果)

  1.首先我们假设d是a和b的最大公约数,则我们可以知道 a可以整除d,表示为a|b,b也可以整除d,表示为b|d,由于r=akbr=a−k∗b 其中a是d的倍数,而且b也是d的倍数,那我们可以得到其实r也是d的倍数,换句话说r也是可以整除d.

  2.接下来我们假设d是b和r的最大公约数,则我们可以知道b可以整除d,表示为b|d,r也可以整除d,表示为r|d,由于a=kb+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是最小的…. 我说的可能太过绝对,以下为他们的具体关系:

                                                                 abra≥b≥r

在我们每轮递归的过程中,希望值是越来越小的…其中a确永远是最大的…而且递归a也是没有意义的…因为我们最终要求的是最大公约数解.

代数形式的推导过程:

欧几里得算法的推导与证明 || 扩展欧几里德算法的解释说明_第1张图片
扩展欧几里德算法的解释说明:

    在学习完上面所讲的欧几里德算法之后,本节我们来讲一下 扩展欧几里得算法,欧几里德算法是用来做什么的呢?
    扩展欧几里德算法是用来在已知a, b求解一组x,y,使它们满足贝祖等式: ax+by=gcd(a,b)ax+by=gcd(a,b),然后再求出现实所所需要的通解。由于证明这个等式成立的过程涉及到其他的数论知识,在学习基础的我们可以暂时把证明过程放在一边,权当这是成立的。

我们已知 ax1+by1=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)=bx2+(a%b)y2=bx2+(afloor(a/b)b)y2gcd(b,a%b)=b∗x2+(a%b)∗y2=b∗x2+(a−floor(a/b)∗b)∗y2
我们最终可以得到:
y1=x2floor(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 呢…
首先我们知道贝祖等式 ax+by=gcd(a,b)a∗x+b∗y=gcd(a,b) 其中agcd(a,b)a≥gcd(a,b)b=0b=0x=1x=1是必然的,满足最终a=gcd(a,b)a=gcd(a,b),而y的取值..由于 b=0b=0 所以y可以取任何值…但是我们最终要求的最小解..所以将其赋值为零…
通过以上的运算过程….我们把ax+by=gcd(a,b)a∗x+b∗y=gcd(a,b)的其中一组解解出来了, 仅仅是其中一组解。对于已经得到的解x1, y1,我们便可以求出通解。
通解计算公式:

x=x0+kt,y=y0+ktx=x0+k∗t,y=y0+k∗t

我们假设 x=x0+ktx=x0+k∗t ,将其带入到 ax+by=gcd(a,b)a∗x+b∗y=gcd(a,b) ,我们可以得到 y=y0ak/bt;y=y0−a∗k/b∗t;
而我们要保证y也为整数的话必须保证a * k /b也为整数,我们不妨令 k=b/gcd(a,b)k=b/gcd(a,b)
所以通解为:
                x=x0+b/gcd(a,b)tx=x0+b/gcd(a,b)∗t
                y=y0a/gcd(a,b)t;y=y0−a/gcd(a,b)∗t;
其中的t就是x,y满足贝祖等式时的周期。

我需要讲的最后一个问题:

      求任何数字n在一定周期t中最小正整数:

int ans = ((n % t)+t) % t;

有关题目:POJ 1601

你可能感兴趣的:(数论)