程序设计方法学第二章作业
一、题目要求:
1.基本要求:
求N个数的最大公约数和最小公倍数。
1.程序风格良好
2.提供友好的输入输出,并进行输入数据的正确性验证。
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
二、算法设计思路
1.基本要求中的算法设计思路:
首先在屏幕显示,提示人员输入N个数,将会对输入的这N个数求最大公约数和最小公倍数,这里要求N>=2。然后借助于for循环,将输入的N个数存入数组中。事先定义好求取两个数的最大公约数和最小公倍数的两个函数,这里需要用到函数的递归调用。还要利用递归来求取N个数的最大公约数和最小公倍数。
2.提高要求中的算法思路:
由题得 :gcd( x , a0)=a1;xb0/gcd(x,b0)=b1;
亦可转化为:x=pa1; p=x/a1; a0=qa1; q=a0/a1;
p,q的关系 :gcd(p,q)==1;
设 gcd(p,q)=K != 1;p=kn;q=km
所以 x=kna1,a0=kma1;
显然 gcd(x,a0)=Ka1 不成立。
可以推广结论:
gcd(x,y)=k 则有 gcd(x/k,y/k)=1
三、源代码
1.基本要求:
#include<stdio.h>
#define N 100
int gcd(int a,int b) //利用辗转相除法中的函数递归调用两个数的最大公约数
{
if(a%b==0)
return b;
else
return gcd(b,a%b);
}
int ngcd(int *a, int n) //主函数中提示输入想要求取最大公约数和最小公倍数的N个数,因数组下标从0开始,故实际下标至n-1数
{
if(n==1)
return *a;
return gcd(a[n-1],ngcd(a, n-1)); //坐标n-1数与前面数的公约数 ,利用递归调用 求取N个数的最大公约数
}
int lcm(int a,int b) //求取两个数的最小公倍数
{
return a*b/gcd(a, b);
}
int nlcm(int *a, int n) //利用递归调用求取N个数的最小公倍数
{
if (n==1)
return *a;
else
return lcm(a[n-1],nlcm(a,n-1));
}
int main()
{
int n,i;
int a[N];
while(1)
{
printf("******请输入N个数,将会对这您输入的这N个数求最大公约数和最小公倍数【n>=2】******\n");
scanf("%d",&n);
if(n==0) break;
for(i=0;i<n;i++)
scanf("%d",&a[i]);
for(i=0;i<n;i++)
printf("%d ",a[i]);
printf(":%d个数\n最大公约数为:%d,最小公倍数为:%d\n",n,ngcd(a,n),nlcm(a,n));
}
return 0;
}
2.提高要求:
#include<iostream>
using namespace std;
int gcd(int a,int b)
{
return a==0?b:gcd(b%a,a); //求取最大公约数
}
int main(){
int a0,a1,b0,b1;
int n,X;
cin>>n;
while(n--){
cin>>a0>>a1>>b0>>b1;
X=0;int p=a0/a1;int q=b1/b0; //确保a0能被a1整除,b1能被b0整除
for(int x=1;x*x<=b1;x++){
if(b1%x==0){
if(x%a1==0 && gcd(x/a1,p)==1 && gcd(b1/x,q)==1) X++;
int y=b1/x; //得到另一个因子
if(y==x) continue;
if(y%a1==0 && gcd(y/a1,p)==1 && gcd(b1/y,q)==1) X++;
}
}
cout<<X<<endl;
}
return 0;
}
四、测试、调试及运行结果截屏
1.基本要求:
测试及调试:
求n个数的最大公约数和最小公倍数未用for循环操作输出时的结果如图1,2;
图1:求n个数的最大公约数和最小公倍数未用for循环操作输出时的编译结果
图2:求n个数的最大公约数和最小公倍数未用for循环操作输出时的运行结果
在这里实现基本要求的输出时,由于未进行for循环,即使系统不会报错,但和我们的目的不符,所以这里需要对数组进行for循环的操作。
运行结果:
求n个数的最大公约数和最小公倍数的运行结果如图3;
图3:n个数的最大公约数和最小公倍数的输运行结果
2.提高要求:
运行结果:
Hankson问题的运行结果如图4:
图4:Hankson问题的运行结果
五、总结
在求N个数的最大公约数和最小公倍数的问题中,可以先对2个数的最大公约数和最小公倍数进行求解,其中可以借助不同的算法求解。然后,我们需要在输入这N个数时用数组来存储,约定从下标0开始,故当求取最大公约数和最小公倍数的N个数时,实际下标至n-1数。其中需要利用到递归调用。需要注意的是在对N个数的最大公约数和最小公倍数的运行结果进行输出时,需要用到for循环。
在Hankson问题的求解之中,将题目要求仔细阅读之后转化为具体问题的求解步骤的探索与总结比较关键。由题得 :gcd( x , a0)=a1;xb0/gcd(x,b0)=b1; 亦可转化为:x=pa1; p=x/a1; a0=qa1; q=a0/a1。p,q的关系 :gcd(p,q)==1;设 gcd(p,q)=K != 1;p=kn;q=km。所以 x=kna1,a0=kma1;显然 gcd(x,a0)=Ka1 不成立。可以推广结论:gcd(x,y)=k 则有 gcd(x/k,y/k)=1。其中x是a1的整数倍而且还是b1的因子。还有循环结构中用到的continue语句语义是结束本次循环,即不再执行循环体中continue语句之后的语句,转入下一次循环条件的判断与执行,并不是break语句跳出了循环。