题目
题目来源:小乐乐与欧几里得_牛客题霸_牛客网 (nowcoder.com)
描述
小乐乐最近在课上学习了如何求两个正整数的最大公约数与最小公倍数,但是他竟然不会求两个正整数的最大公约数与最小公倍数之和,请你帮助他解决这个问题。
输入描述:
每组输入包含两个正整数n和m。(1 ≤ n ≤ 109,1 ≤ m ≤ 109)
输出描述:
对于每组输入,输出一个正整数,为n和m的最大公约数与最小公倍数之和
示例1
输入:
10 20
输出:
30
示例2
输入:
15 20
输出:
65
暴力解法
最大公约数
什么是约数,就是能被整除的那个数,公约数就是两个数都能整除的数字,那么最大公约数就是两个数都能整除的数中最大的那一个数
那么我们不妨思考,如何才能得到两个数的最大公约数呢?
假设两个数字为a
,b
那么公约数是不是必定小于等于两个数中更小的那一个,为什么?因为你的数字如果比任何一个数大,都无法满足约数这个条件。因此,我们就可以设定一个循环,让它从两个数字中更小的那个开始自减,直到找到第一个约数,那么这个数字就是最大的公约数
代码如下
long long Max(long long x, long long y) {
if(x > y){
long long tmp = x;
x = y;
y = tmp;
}
for(int i = x;i > 1;i++){
if(x % i == 0 && y % i == 0){
return i;
}
}
return 1;
}
最小公倍数
那么我们对最小公倍数的求法也是同理的,是从两个数中最大的那一个数开始一个一个找,都是一样的写法就不多赘述了
long long Min(long long x, long long y) {
if(x > y){
long long tmp = x;
x = y;
y = tmp;
}
long long i = y;
while(!(i % y == 0 && i % x == 0)){
i++;
}
return i;
}
那么如果你用上面的这两个暴力解法,去求和提交代码,是肯定过不了的,会提示您的程序未能在规定时间内运行结束,请检查是否循环有错或算法复杂度过大
也就是说暴力解法在这里是无法通过的,那么接下来我们就要运用一些数学上的方法来解决这个问题
代码优化
原理讲解
这里实际上就要用到十分知名的求最大公约数算法,辗转相除法
这里我们设a
,b
是我们要求的数且此时a
>b
,将a
/b
得出余数K1
,并且将b
作为下一次的除数(下一次运算的a)K1
作为下一次的被除数(下一次运算的b)。每进行一次计算就将上一次的被除数作为这一次计算的除数,上一次的余数作为被除数,直到求到的余数为0为止,那么此时的b就是最大公约数。
当Kn = 0
时,Kn-1
为最大公约数
这里证明还是有点难度的,并且也不是很容易理解。但是可以举一个例子来帮助理解
下面是K4 = 0
的计算例子
你会发现,如果我们不断的往回带,最终a
和b
的所有单项式里面一定会出现K3
那么我们就可以用代码实现一下这个算法
long long Max(long long x, long long y) {
//先保证x是大于y的
if(x > y){
long long tmp = x;
x = y;
y = tmp;
}
long long tmp;
//当余数不为0时,一直辗转
while(x % y){
tmp = x % y;
x = y;
y = tmp;
}
//此时余数为0,此时的被除数y为最大公约数
return y;
}
那么接下来我们也要利用这个最大公约数求出最小公倍数
假如求a
和b
的最小公倍数,其最大公约数是r
,那么用到的公式是a*b/r
(由最大公约数和最小公倍数的定义得出:两个整数的乘积等于它们的最大公约数与最小公倍数的乘积)
那么只需要套公式就可以写出最后的代码
long long min = a*b/max;
代码总览
#include <stdio.h>
long long Max(long long x, long long y) {
if(x > y){
long long tmp = x;
x = y;
y = tmp;
}
long long tmp;
while(x % y){
tmp = x % y;
x = y;
y = tmp;
}
return y;
}
int main() {
long long a, b;
while (scanf("%lld %lld", &a, &b) != EOF) {
long long max = Max(a, b);
long long min = a*b/max;
printf("%lld", max + min);
}
return 0;
}