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

首先欧几里得是谁???

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

欧几里得(希腊文:Ευκλειδης ,公元前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;
}





  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值