关于求多个数最大公约数和最小公倍数的问题以及Hankson趣味题

题目1:

求N个数的最大公约数和最小公倍数。用C或C++或java或python语言实现程序解决问题。求N个数的最大公约数和最小公倍数。用C或C++或java或python语言实现程序解决问题。

题目2:

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

算法思路:

       第一个题目是求多个数的最大公约数和最小公倍数,根据上次编写的求两个数最大公约数和最小公倍数的经验来看,我将辗转相除法应用了进来,首先求得前两个数的最大公约数,然后利用求得的这个最大公约数再去与第三个数用同样的方法求其最大公约数,按此规律逐步求下去,直到走完所有数据,最终所求得的数就是最终结果即这些数的最大公约数。求多个数的最小公倍数,首先将这些数相乘,然后用其乘积对每一个数进行除法运算,将结果记录下来,然后对这些数求最大公约数,然后用前面的乘积除以这个最大公约数,即得到最小公倍数。

       第二个题目求满足条件x和a0的最大公约数是a1、x和b0的最小公倍数是b1的x的个数,可以利用约束条件来进行求解。首先x取值必在【a1,b1】这个区间或者x取值b1,以此作为一个约束条件。然后再先满足gcd(x/a1,a0/a1)==1,其次由于x和b0的最小公倍数为b1,则有x*b0/b1=gcd(x,b0),同样,还需要满足条件gcd(x/(x*b0/b1),b0/(x*b0/b1))==1即gcd(b1/b0,b1/x)==1.用此条件作为约束,,从而完成程序。

程序源代码:

#include <iostream>
using namespace std;
#define MAXLEN 15
int Gcd(int s[],int n)/*计算多个数的最大公因数*/
{
	int i,x,temp,gcd;/*定义变量temp为交换数值时中间变量,gcd为两个数临时的最大公因数*/
    gcd=s[0];
	i=1;
    while(i<n)/*开始n-1次循环,先求解数组前两个数的最大公因数,然后用求得的最大公因数再与数组的下一个数求最大公因数,如此循环,直到走完数组所有数据*/
	{
		x=s[i];
		if(gcd<x)/*交换使两个数的较大值给gcd,较小值给x*/
		{
			temp=x;
			x=gcd;
			gcd=temp;	
		}
		do/*辗转相除法求解*/
		{
			temp=gcd%x;
			gcd=x;
			x=temp;
		}while(x!=0);
		i++;
	}
	return gcd;/*返回多个数的最大公因数*/
}
int Gcd_1(int a,int b)/*计算两个数的最大公约数*/
{
	int temp;
	if(a<b)
	{
		temp=a;
		a=b;
		b=temp;
	}
	do
	{
		temp=a%b;
		a=b;
		b=temp;
	}while(b!=0);
	return a;
}
int Multiple(int s[],int n)/*求最小公倍数*/
{
	int gcd,k[MAXLEN],mut,i,product=1;/*gcd为数组s中数据的乘积依次除以每个数后形成的数组的数组元素的最大公因数*/
	for(i=0;i<n;i++)/*计算数组s的所有数组元素的乘积*/
	{
		product*=s[i];
	}
	for(i=0;i<n;i++)/*计算数组s中数据的乘积依次除以每个数后形成的数组k*/
	{
		k[i]=product/s[i];
	}
	gcd=Gcd(k,n);/*计算数组k的所有元素的最大公因数*/
    mut=product/gcd;/*计算数组s的所有元素的最小公倍数*/
	return mut;/*返回最小公倍数*/
}
int Getx(int a,int b,int c,int d)/*计算按规则输入的四个数满足一定条件的x的数量,a,b,c,d分别取a0,a1,b0,b1的值*/
{
	int count=0;/*定义计数变量count*/
	for(int i=b;i<=d/2;i++)/*要满足条件x和c的最大公倍数为d,则x一定不会出现在(d/2,d)这个区间*/
	{
		if((i%b==0)&&(d%i==0))/*判断是否满足条件x为d的倍数以及x是否为d的约数*/
			if(Gcd_1(i/b,a/b)==1&&Gcd_1(d/c,d/i)==1)/*判断是否满足具体的两个条件*/
			   count++;
	}
	i=d;
	if(i%b==0)/*判断d本身是否满足具体条件*/
		if(Gcd_1(i/b,a/b)==1&&Gcd_1(d/c,d/i)==1)
			count++;
	return count;/*返回满足条件x的个数*/
}
int main()
{
	int i,m,gcd;
	int s[MAXLEN];
	int t[MAXLEN][4],n,z;
	int a0,a1,b0,b1;
    cout <<"第一部分:求多个数据的最大公约数和最小公倍数"<<endl;
	cout <<"请输入数据个数:"<<endl;
	cin >>m;
	cout <<"请输入数据:"<<endl;
	i=0;
	while(i<m)
	{
		cin >>s[i];
	    if(s[i]>0)
		    i++;
		else
			cout <<"请输入正整数!";
	}
	cout <<"这些数据的最大公约数为:"<<Gcd(s,m)<<endl;
	cout <<"这些数据的最小公倍数为:"<<Multiple(s,m)<<endl;
    cout <<"第二部分:求按一定规则输入的四个数满足一定条件的x的个数"<<endl;
	cout <<"请输入组数:";
	   cin >>z;
	i=0;
	while(i<z)
	{
		cout <<"请依次输入满足条件(a0能被a1整除,b1能被b0整除)的数据a0,a1,b0,b1:"<<endl;
		for(int j=0;j<4;j++)   
		   cin >>t[i][j];
		if(t[i][0]>0&&t[i][1]>0&&t[i][2]>0&&t[i][3]>0)
		{
			if(t[i][0]%t[i][1]==0&&t[i][3]%t[i][2]==0)
			   i++;
			else
			   cout <<"请按规则输入数据!";
		}
		else
			cout <<"请按规则输入数据!";
	}
	cout <<"这几组满足条件的x个数分别为"<<endl;
	for(i=0;i<z;i++)
	{
		a0=t[i][0];
		a1=t[i][1];
		b0=t[i][2];
        b1=t[i][3];
		n=Getx(a0,a1,b0,b1);
		cout <<n<<endl;
	}
	return 0; 
}

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值