第二次作业
1.问题描述:
1, 求多个数的最大公约数,最小公倍数。
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的个数。请你帮助他编程求解这个问题。
2.问题分析
对第一个问题,求多个数的最大公约数和最小公倍数,可以拆分成求多组数的最大公约数和最小公倍数,基本思路是求得前两个数的最大公约数和最小公倍数后依次与后一个数组合再求新的最大公约数和最小公倍数,当和最后一个数求完后结果即为这组数的最大公约数和最小公倍数。
对第二个问题,由于x和a0能被a1整除,x一定是a1的倍数,同时b1又能被x和b0整除,问题归结为已知两数中的一数和他们的最大公约数和最小公倍数,求另外一数,基本思路为可使x取a1的倍数,让x在循环里倍数增长,只需再循环里判断x和b0的最小公倍数是否是b1即可,是则输出,否则x在原来基础上加a1,继续判断。
程序流程图如下:
3.代码实现
#include<iostream>
using namespace std;
#define N 100
int divisor(int, int);//求最大公约数
int multiple(int,int);//求最小公倍数
void gcd_mul();//求几个数的最大公约数,最小公倍数
void hankson();//求hankson问题
void main()
{
cout << "输入一串打大于0的整数,以0标志输入结束:" << endl;
gcd_mul();
hankson();
system("pause");
}
int divisor(int x, int y)//最大公约数
{
int temp(0);
if (x < y)
{
temp = x;
x = y;
y = temp;
}
if (x%y==0)
return y;
while (y != 0)
{
temp = x % y;
x = y;
y = temp;
}
return x;
}
int multiple(int x, int y)//最小公倍数
{
int temp;
temp=divisor(x,y);
return (x * y / temp);
}
void gcd_mul()//求多个数的最大公约数,最小公倍数
{
int x[N], i = 0;
int temp_div,temp_mul;
int j = 2;
//输入一组数,存入数组
do
{
cin >> x[i];
} while (x[i++] != 0); //求出前两个数的最大公约数,最小公倍数
temp_div = divisor(x[0], x[1]);
temp_mul = multiple(x[0], x[1]); //通过循环依次求出前两个数与第三个数的最大公约数,最小公倍数
while (x[j]!= 0)
{ temp_div = divisor(temp_div,x[j]);
temp_mul = multiple(temp_mul,x[j]);
j++;
}
cout << "最大公约数:" << temp_div << endl;
cout << "最小公倍数:" << temp_mul << endl;
}
//hankson问题
void hankson()
{
int x[10][4];
int n,i(0),j(0);
int count(0);
cout << "输入数据组数:\n" ;
cin >> n;
cout << "输入数据a0,a1,b0,b1,要求a0能整除a1,b0能整除b1" << endl;
//把输入的数据组存入二维数组
do
{
if (j < 4)
{
cin >> x[i][j];
j++;
}
else
{
i++;
j = 0;
}
} while (x[i][0]!=0);
i = 0;
int q=x[0][1] ;//先假定x=a1
int tempt ;
//依次判断每组数是否有满足条件的x
while (x[i][0] != 0)
{
q = x[i][1];
while ( q <=x[i][3])
{
tempt = multiple(q, x[i][2]);//x和b0的最小公倍数等于b1,则满足条件
if (tempt == x[i][3])
{
count++;//个数加1
}
q +=x[i][1];
}
if(q%x[i][0]==0)//q如果是第一个数的倍数,则x和a0的最大公约数就不再是a1,所以要跳过,继续加a0
q +=x[i][1];
if (count == 0)
cout << "不存在这样的x" ;
i++;//继续下一组数,count归0
cout << endl;
count=0;
}
}
4.调试及测试运行结果
由于这个程序主要是几个函数构成,依次检测即可
调用divisor()函数求最大公约数divisor(6,9)
调用multiple()函数求最小公倍数multiple(6,9)
调用gcd_mul()函数求多个数最大公约数,最小公倍数
调用hankson()函数求hankson问题
程序运行结果如图:
5.总结
此次编程,在hankson()函数的编写上耗时最多,个人感觉也是最难的一部分,难在构建循环时在思路和程序实现的链接上,思路很清晰,但构建循环出了几次错,搞成了死循环,回想了一下主要犯了以下几个错误,一个是对循环条件的设置出了问题,二是对x以a1位为倍数增长的语句书写,绝对不能写成x+=x这样的语句,虽然看上去确实是变为原来的2倍,但仅限于第一次,第二次x就变成原来的4倍了,三是没考虑到x增长时有可能变为a0的倍数,这样的话x和a0的最大公约数将不再是a1,而是a1,四是在找合适的x时,循环结束条件的设置,整体思路是让x以a1为基础,一倍一倍地增长,不断和b0求最小公倍数,如果和b1相等则找到一个值,一开始设置的条件是x和b0的乘积大于b1的话就结束循环,显然有问题,最后改为x大于b1则结束循环,最后还有个小问题就是判定完一组数据要将计数器count归0,总结下来一句话就是多想想,考虑充分,全面,对多组数据进行判断是一定要理清楚内外层循环的循环体和循环条件。