欧几里得算法(辗转相除)及其扩展证明

来源:互联网 发布:淘宝号怎么申请注册 编辑:程序博客网 时间:2024/06/07 04:48

首先欧几里得是谁???

学数学的人一定不陌生,一位为数学界做出重大贡献的人;(以下摘自百度百科)

欧几里得(希腊文:Ευκλειδης ,公元前330年—公元前275年),古希腊数学家。他活跃于托勒密一世(公元前364年-公元前283年)时期的亚历山大里亚,被称为“几何之父”,他最著名的著作《几何原本》是欧洲数学的基础,提出五大公设,欧几里得几何,被广泛的认为是历史上最成功的教科书。欧几里得也写了一些关于透视、圆锥曲线、球面几何学及数论的作品。(有兴趣的人可以自行百度)

那么欧几里得算法又是什么呢?

这个名字大家可能会有点陌生,但是辗转相除法肯定听说过,没错,欧几里得算法就是辗转相除法的大名,而辗转相除法则像一个外号;

欧几里得算法可以这样描述:有正整数a,b(a>b);a=n*b+r(n, r均为正整数);则a, b的最大公约数等于b, r的最大公约数;

公式表示为gcd(a,b)= gcd(b,a%b);(PS:gcd是greater common divisor(最大公约数)的缩写);

证明:

方法一:

假设 d为a,b的公约数,则d|a, d|b(d|a表示a能被d整除); 令a=x*d, b=y*d;则r=a-n*b=x*d-n*y*d=(x-n*y)*d; 所以r|d;所以d为b,a%b的公约数;

假设d为b,r的公约数;因为a=n*b+r;同理可得d|a;所以d为a,d的公约数;

综上所述:a,b的公约数=  b,a%b的公约数

那么同理gcd(a, b)=gcd(b, a%b);

方法二:

若gcd(a, b)=gcd(b, r)成立(r=a%b), 令c=gcd(a,b);a=m*c,b=n*c, 且n,m互质;

因为r=a%b,r=a-kb=m*c-kn*c=(m-k*n)*c;

假设n和(m-k*n)不互质,则n=x*d,(m-k*n)=y*d(d>1),m=y*d+k*x*d=(y+k*x)*d;a=m*c=(y+k*x)*d*c, b=n*c=x*d*c;所以a,b的最大公约数,与前提矛盾,所以n,(m-k*n)互质;

所以gcd(a,b)=gcd(b,a%b);

证明结束;

那么,该算法可以解决什么问题呢?很显然是求两个数的最大公约数了;

好,你一定迫不及待要看代码实现了,take it easy,NOW show U:

#include <iostream>using namespace std;//递归实现:int gcd_1(int a, int b){             return a%b==0? b : gcd_1(b, a%b);}//迭代实现:int gcd_2(int a, int b){            while(b){        int c=b;        b=a%b;        a=c;    }    return a;}int main(){    int a, b;    cin >> a >> b;    if(a<b){        a=a+b;        b=a-b;        a=a-b;    }    int gcd1, gcd2;    gcd1=gcd_1(a, b);    gcd2=gcd_2(a, b);    cout << "gcd1: " << gcd1 << endl;    cout << "gcd2: " << gcd2 << endl;    return 0;}

现在了解一下扩展欧几里得算法:

对于非负整数a,b必然存在整数对x,y使得a*x+b*y=gcd(a,b);(PS: x,y∈Z);

证明:

令a*x1+b*y1=gcd(a, b) (1) ; b*x2+a%d*y2=gcd(b, a%b) (2);

在计算机中a%d=a-(a/b)*b;所以(2)式可化简为 a*y2+b*(x2-(a/b)*y2)=gcd(b,a%b);

因为gcd(a, b)==gcd(b, a%d) , 所以a*x1+b*y1==a*y2+b*(x2-(a/b)*y2), 所以x1==y2, y1==(x2-(a/b)*y2);

由此我们可以看出x1,y1与x2,y2有关;但是x2,y2又怎么求呢????

我们可以取一个极值;当b=0时 gcd(a, b)=a;a*x+b*y=gcd(a, b)=a; 此时x,y有唯一解x=1,y=0(PS:其实唯一解这一说法不严谨,应该是x有唯一解:x=1;y可以是任意整数,此处为了简单化令y=0;当然无论y取何值都是可以的,不过此时y的取值决定了之后的x,y的解,毕竟a*x+b*y=gcd(a,b)的解不唯一);

有了极值之后,也就是有了递归的终点,那么就可以递归求出a*x+b*y=gcd(a,b)中x,y的一个解;

OK,SHOW U THE CODE:

#include <iostream>using namespace std;//函数返回值r表示a,b的最大公约数;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;    x=y;    y=t-a/b*y;    return r;}int main(){    int a, b;    cin >> a >> b;    if(a<b){        a=a+b;        b=a-b;        a=a-b;    }    int x, y;    int r=exgcd(a, b, x, y);    cout << r << ' ' << x << ' ' << y;    return 0;}