一行代码求出两个数的最大公约数与最小公倍数

欧几里得算法求最大公约数

如果设两个数为a,b,他们的最大公约数是gcd(a,b),那么可以得出gcd(a,b)= gcd(b,a mod b),于是有下面求两个数最大公约数的欧几里得算法

int gcd (int a,int b){
    return b ? gcd(b,a % b): a;//a和0的最大公约数是a  因为0可以整除任何数
}

非常精简,就一句话,必背算法之一。下面来证明为什么gcd(a,b)= gcd(b,a mod b)。

首先按照常识,我们可以知道一个数d 能整除 a,也能整除b ===> d能整除x *a + y * b(x,y为整数,类似线性组合).

而且

\[a mod b = a - \lfloor \frac{a}{b}\rfloor\cdot b 。其中\lfloor \frac{a}{b}\rfloor是一个整数。所以a modb是a,b的线性组合 \]

因为对于a,b的所有公约数,都能整除a,b所以他们都能整除a mod b,所以得出(1)任何一个a,b的公约数都是b, a mod b的公约数。

同理对于b, a mod b的任意一个公约数k,都能整除b和a mod b ,而且

\[a mod b = a - \lfloor \frac{a}{b}\rfloor\cdot b \]

那么k 肯定能整除

\[a - \lfloor\frac{a}{b}\rfloor \cdot b + \lfloor\frac{a}{b}\rfloor\cdot b = a 其中\lfloor\frac{a}{b}\rfloor是整数 \]

因为可以把这个式子看作是a mod b 与b的线性组合。所以对于b,a mod b的所有公约数都能整除 a,b.所以得出(2)任意b,a mod b的公约数都是a ,b的公约数

由(1)(2)得 a ,b得公约数与b, a mod b的公约数相同 ===> 所以他们的最大公约数肯定相同。即gcd(a,b) = gcd(b,a mod b)。

所有用递归就可以写出这个算法,

注意:当b = 0的时候,a 和0的最大公约数是 a。

求最小公倍数

如果是两个数a,b,最大公约数为c,只要将ab两数相乘,再除以c即可。因为两数相乘时,公约数部分乘了两次,所以要除以公约数一次,所以两个数a,b,最大公约数为c,最小公倍数是ab/c。

所以求最小公倍数的算法如下

int lcm(int a,int b){
    return a * b / gcd(a,b);
}

也是十分精简的算法。

扩展欧几里得算法

裴蜀定理:对于任意正整数a,b一定存在非零整数x,y使得

ax + by = gcd(a,b)

现在有一道题 要求:

给定n对正整数ai,bi,对于每对数,求出一组xi,yi,使其满足ai∗xi+bi∗yi=gcd(ai,bi)。

可以使用扩展欧几里得算法来在运行欧几里得算法的同时,顺便把x,y求出来。

结合欧几里得算法与裴蜀定理可以得:

\[by + (a mod b)x = gcd(b,a mod b) = gcd(a,b) \]

\[因为a mod b = a - \lfloor \frac{a}{b} \rfloor b 所以可以得到by + (a- \lfloor\frac{a}{b}\rfloor)x = gcd(b,amodb) = gcd(a,b) \]

\[整理可以得到 ax + b(y - \lfloor \frac{a}{b} \rfloor x) = gcd(b,amodb) =gcd (a,b) \]

所以这层x不用变,只要将y更新为 y - (a /b) * x即可

#include <iostream>
using namespace std;
//执行欧几里得算法的同时顺便把x,y给求出来,所以用引用进行传参
int exgcd(int a,int b,int &x,int &y) {
    if(!b) {
        x = 1, y = 0;//边界情况 就是b = 0的时候,明显公约数是a,而且就是x = 1 y =0 刚好就是1* a + 0 * b =a ;
        return a;
    }
    int d = exgcd(b,a % b,y,x);
    y -= (a / b) * x;//这层x不用变,只要将y更新为 y - (a /b) * x即可
    return d;
}

int main(){
    int n ;
    cin >> n;
    while(n --) {
        int a,b,x,y;
        scanf("%d%d",&a,&b);
        exgcd(a,b,x,y);
        printf("%d %d\n",x,y);
    }
    return 0;
}
posted @ 2020-08-27 22:50  驿站Eventually  阅读(1089)  评论(0编辑  收藏  举报