求最大公约数及Hankson趣味题

一、问题说明

基础:
求N个数的最大公约数和最大公倍数。
提高:
Hanks博士是BT(Bio-Tech,生物技术)领域的知名专家,他的儿子名叫Hankson。现在,刚刚放学回家的Hankson正在思考一个有趣的问题。
今天在课堂上,老师讲解了如何求两个正整数c1和c2的最大公约数和最小公倍数。现在Hankson认为自己已经熟练地掌握了这些知识,他开始思考一个“求公约数”和“求公倍数”之类问题的“逆问题”,这个问题是这样的:已知正整数a0,a1,b0,b1,设某未知正整数x满足:
1、 x和a0的最大公约数是a1;
2、 x和b0的最小公倍数是b1。
Hankson的“逆问题”就是求出满足条件的正整数x。但稍加思索之后,他发现这样的x并不唯一,甚至可能不存在。因此他转而开始考虑如何求解满足条件的x的个数。请你帮助他编程求解这个问题。
输入格式
输入第一行为一个正整数n,表示有n组输入数据。接下来的n行每行一组输入数据,为四个正整数a0,a1,b0,b1,每两个整数之间用一个空格隔开。输入数据保证a0能被a1整除,b1能被b0整除。
输出格式
输出共n行。每组输入数据的输出结果占一行,为一个整数。
对于每组数据:若不存在这样的x,请输出0;若存在这样的x,请输出满足条件的x的个数;
样例输入
2
41 1 96 288
95 1 37 1776
样例输出
6
2

二、分析

1、基础

用一数组a[]存储输入的N个数,先用gcd()求两个数的最大公约数,然后求a[1]=gcd(a[0],a[1]),再求a[2]=gcd(a[1],a[2]),依次下去,最后a[N-1]既是结果。最小公倍数则调用lcm()。

2、提高

已知
gcd(x,a0)=a1……①
lcm(x,b0)=b1;
根据两个数的最大公约数和最小公倍数的关系,mn/gcd(m,n)=lcm(m,n);
转化得,gcd(x,b0)=x
b0/b1……②
由①②根据最大公约数的性质得,
gcd(x/a1,a0/a1)=1……③
gcd(b1/b0,b1/x)=1……④
符合条件的x必然满足③式和④式,故枚举b1的因子且满足③、④式就是x。
算法流程图
在这里插入图片描述

三、运行结果

1、基础

在这里插入图片描述

2、提高

在这里插入图片描述

四、程序实现

1、N个数的最大公约数

* 名称:第二次作业
* 文件名:基础.cpp
* 说明:多个数的最大公约数及最小公倍数
*/
#include"iostream"
using namespace std;

//求最大公约数
int gcd(int a,int b)
{
	int ans = 1;//储存第一步中约掉的若干个2
	int gcd;//储存最终返回的结果 
	while (a % 2 == 0 && b % 2 == 0)//如果a,b均为偶数则用2约简 
	{
		a /= 2;
		b /= 2;
		ans *= 2;
	}
	while (a != b)//判断两数是否相等,相等则得出最大约数
	{
		if (a > b)
			a -= b;//以较大的数减较小的数
		else
			b -= a;//以较大的数减较小的数
	}
	gcd = a * ans; //求第一步中约掉的若干个2与第二步中等数的乘积 
	return gcd;
}

//求最小公倍数
int lcm(int a, int b) {
	return(a*b / gcd(a, b));
}

int main() {
	int a[1000];
	int temp1, temp2;
	int i = 0;
	cin >> i;//输入需要几个数
	for (int j = 0; j < i; j++) {
		cin >> a[j];
	}
	for (int k = 0; k < i - 1; k++) {
		temp1 = a[0];
		temp1 = gcd(temp1, a[k + 1]);
	}
	for (int k = 0; k < i - 1; k++) {
		temp2 = a[0];
		temp2 = lcm(temp2, a[k + 1]);
	}
	int gcd = temp1;
	cout << "最大公约数 " << temp1 << endl;
	int lcm = temp2;
	cout << "最小公倍数 " << temp2 << endl;
	system("pause");
}

2、Hankson问题

*	名  称:第二次作业
*	文件名:homework2.cpp
*	说  明:Hankson问题实现
*/

#include"iostream"
using namespace std;

//求最大公约数
int gcd(int a, int b) 
{
	int ans = 1;//储存第一步中约掉的若干个2
	int gcd;//储存最终返回的结果 
	while (a % 2 == 0 && b % 2 == 0)//如果a,b均为偶数则用2约简 
	{
		a /= 2;
		b /= 2;
		ans *= 2;
	}
	while (a != b)//判断两数是否相等,相等则得出最大约数
	{
		if (a > b)
			a -= b;//以较大的数减较小的数
		else
			b -= a;//以较大的数减较小的数
	}
	gcd = a * ans; //求第一步中约掉的若干个2与第二步中等数的乘积 
	return gcd;
}

int main() {
	int n;//n组数据
	cin >> n;
	int a0, a1, b0, b1;//正整数a0,a1,b0,b1
	for (int i = 1; i <= n;i++) {
	int num = 0;
	cin >> a0 >> a1 >> b0 >> b1;
	//	枚举b1的因子,判定条件为j*j<=b1,防止重复记录同一个因子
		for (int j = 1; j*j <= b1; j++) {
			if (b1%j == 0) {
				int x = j;
				if (x%a1 == 0)
					//判断最大公约数是否为1
					if (gcd(x / a1, a0 / a1) == 1 && gcd(b1 / b0, b1 / x) == 1)
						num++;
				x = b1 / x;
				if(x != j && x % a1 == 0)
					if (gcd(x / a1, a0 / a1) == 1 && gcd(b1 / b0, b1 / x) == 1)
						num++;
			}
		}
		cout << num << endl;
	}
	system("pause");
	return 0;
}

五、个人总结

数学的学习与算法的设计是紧密结合的,本次作业中核心的就在于对最大公约数的数学知识的充分了解,并且结合计算机的优势,可以不断循环计算。两者结合能够很有效的解决一些问题。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值