51NOD 1011 最大公约数GCD 1012最小公倍数LCM

GCD=Greatest Common Divisor,最大公约数。
LCM=Least Common Multiple,最小公倍数。
如果之前没有学过算法,最粗暴的方法是从较小的数(不含)向下遍历,遇到的第一个能同时被整除的数就是,不过到1了还没有,那就是1。
如果我们很不幸地遇到了两个质数,或者两个公因子特别小的数,仅遍历的复杂度就已经到了O(n),取余还不算。
如果我们想模拟人类操作,用短除法去做,中间有一步是不明确的,就是“看出”一个较小的因子,事实上我们手算时经常也需要尝试多次才能找到。

辗转相除法(欧几里得算法)是一种常用的方法,它的核心是
a,b的GCD是b,a%b的GCD。
由带余除法容易知道a%b<b,所以每次的解空间至少除以2,复杂度约为O(1/2^n),是一种高效解。
b是下一次的a,a%b是下一次的b。
如果a%b=0,自然b就已经是最大公约数,程序结束。

#include <stdio.h>
int gcd(int a,int b)
{	
	if(b==0) return a;
	else
		return gcd(b,a%b);
}

int main(int argc, char const *argv[])
{
	int a,b;
	scanf("%d%d",&a,&b);
	printf("%d",gcd(a,b));
	return 0;
}

也可以把函数写的更紧凑。

int gcd(int a,int b) {return b==0?a:gcd(b,a%b);}

一般不要刻意去追求把代码写得紧凑,因为虽然现在看起来是比较简单,但经过编译器优化之后,两者的代码其实差不多,甚至可能是一样的,效率依靠的是算法,不是代码。
其实最大公约数也有着很大的缺陷,先马着。

最小公倍数

一般运用
a与b的乘积是a、b的最小公倍数与最大公约数的乘积
即可。
当数字不太大时,很容易可以写出:

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

最好先做一次除法,毕竟gcd一定是因数,可以整除,这样可以控制数据规模,防止过限。

#include <stdio.h>
long long gcd(long long a,long long b) {return b==0?a:gcd(b,a%b);}
long long lcm(long long a,long long b) {return a*(b/gcd(a,b));}

int main(int argc, char const *argv[])
{
	long long a,b;
	scanf("%lld%lld",&a,&b);
	printf("%lld",lcm(a,b));
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_43873801/article/details/86482445
今日推荐