01-求最大公约数与最小公倍数

01-求最大公约数与最小公倍数


前几天,和一哥们聊天,哥们突然提到了求解最大公约数的问题,我不假思索地回答暴力破解啊,哥们呵呵不语,吾顿感不爽,于是有了以下的狂补。

一. 辗转相除法

辗转相除法又名欧几里德算法(Euclidean algorithm)乃求两个正整数之最大公因子的算法。它是已知最古老的算法, 其可追溯至公元前300年前(摘自百度百科)。其具体算法过程如下:假设有正整数a与b,求a与b的最大公约数即是求解b与c=a%b的最大公约数,一致到c为0为止。则最小公倍数既是a与b的乘积除以a与b的最大公约数。不说了上代码。

//--1 迭代版本 --//
#include <iostream>
using namespace std;

int main(void){
    int a,b,m,n;
    cin>>a>>b;
    m =a;
    n =b;
    int c=a%b;
    while(c){
        a = b;
        b =c;
        c = a%b;
    }
    cout<<m<<"与"<<n<<"最大公约数为:";
    cout<<b<<endl;
    cout<<m<<"与"<<n<<"最小公倍数为:";
    cout<<m*n/b<<endl;
}

//--2 递归版本 --//
#include <iostream>
using namespace std;

int gcd(int m,int n){
    if(!(m%n))return(n);
    else    gcd(n, m%n);
}

int main(void){
    int a,b,m,n;
    cin>>a>>b;
    m =a;
    n =b;
    b=gcd(m,n);
    cout<<m<<"与"<<n<<"最大公约数为:";
    cout<<b<<endl;
    cout<<m<<"与"<<n<<"最小公倍数为:";
    cout<<m*n/b<<endl;
}

二. 辗转相减法

辗转相减法(求最大公约数),即尼考曼彻斯法,其特色是做一系列减法,从而求得最大公约数(摘自百度百科)。这样可以避免如果数字过大时取余带来的不便。算法思想如下,假设有正整数a与b,求a与b的最大公约数即是求解b与c=a-b的最大公约数,一致到c为0为止。则最小公倍数既是a与b的乘积除以a与b的最大公约数。代码如下:

//--1 迭代版本 --//
#include <iostream>
using namespace std;

int main(void){
    int a,b,m,n,c;
    cin>>a>>b;
    m =a;
    n =b;
    if(a<b){
        int t=a;
        a =b;
        b=t;
    }
    c = a-b;
    while(c){
        a = b>c?b:c;
        b = b<c?b:c;
        c =a-b;
    }
    cout<<m<<"与"<<n<<"最大公约数为:";
    cout<<b<<endl;
    cout<<m<<"与"<<n<<"最小公倍数为:";
    cout<<m*n/b<<endl;
}
//--2 递归版本 --//
#include <iostream>
using namespace std;

int gcd(int m,int n){
    if(m<n){
        int t=m;
        m =n;
        n =t;
    }

    if(!(m-n))return(n);
    else    gcd(n, m-n);
}

int main(void){
    int a,b,m,n;
    cin>>a>>b;
    m =a;
    n =b;
    b=gcd(m,n);
    cout<<m<<"与"<<n<<"最大公约数为:";
    cout<<b<<endl;
    cout<<m<<"与"<<n<<"最小公倍数为:";
    cout<<m*n/b<<endl;
}

三. 辗转相减法与辗转相除法相结合

辗转相除法与辗转相减法,各有优缺点又各有长度,为了取其各处的有点,此处将二者结合起来来克服各自的缺点。其算法如下:假设有正整数a与b,若a与b均为偶数,则将a与b均右移一位,并将基数base *2,若a与b仅有一个为偶数,则将a或b右移一位,然后使用辗转相减法,代码如下:

//--1 迭代版--//
#include <iostream>
using namespace std;

int main(void){
    int a,b,m,n,c,base=1;
    cin>>a>>b;
    m =a;
    n =b;
    a = n<m?m:n;
    b = n<m?n:m;
    while(a%2 == 0 && b%2 == 0) {
        base <<=1;
        a >>= 1;
        b >>= 1;
    }

    while(a%2 ==0 ) a >>= 1;
    while(b%2 ==0 ) b >>= 1;
    int t=a;
    a = a<b?b:a;
    b = t<b?t:b;
    c = a-b;
    while(c){       
        while(a%2 == 0 && b%2 == 0) {
            base <<=1;
            a >>= 1;
            b >>= 1;
        }

        while(a%2 == 0 ) a >>= 1;
        while(b%2 == 0 ) b >>= 1;
        a = b>c?b:c;
        b = b<c?b:c;
        c =a-b;
    }
    cout<<m<<"与"<<n<<"最大公约数为:";
    cout<<b*base<<endl;
    cout<<m<<"与"<<n<<"最小公倍数为:";
    cout<<m*n/b/base<<endl;
}

//--2 递归版-- //
#include <iostream>
using namespace std;

int gcd(int a, int b){
    int t=a, base=1;
    a = a<b?b:a;
    b = t<b?t:b;

    if(a%b ==0) return(b);
    else{
        while(a%2 == 0 && b %2 ==0 ){
            base <<=1;
            a >>=1;
            b>>=1;
        }
        while(a%2==0) a>>=1;
        while(b%2==0) b>>=1;
        t =a;
        a = a<b?b:a;
        b = t<b?t:b;
        return base*gcd(b,a-b);
    }
}

int main(void){
    int a,b,m,n;

    cin>>a>>b;
    m = a;
    n =b;
    b = gcd(a,b);
    cout<<m<<"与"<<n<<"最大公约数为:";
    cout<<b<<endl;
    cout<<m<<"与"<<n<<"最小公倍数为:";
    cout<<m*n/b<<endl;
}

本人能力有限,编写的代码比较粗鄙,仅作本人学习所用,如有不正确之处,很高兴您能给指出来。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值