PTA上C语言程序设计练习题,包含 换硬币、水仙花数、最大公约数最小公倍数、高空坠球、猴子吃桃、兔子繁衍、出租车计价、三角形判断、简单计算器、平面向量加法。
这些题需要一些细节或思维。
1.换硬币:
习题4-5 换硬币 (20 分)
将一笔零钱换成5分、2分和1分的硬币,要求每种硬币至少有一枚,有几种不同的换法?
输入格式:
输入在一行中给出待换的零钱数额x∈(8,100)。
输出格式:
要求按5分、2分和1分硬币的数量依次从大到小的顺序,输出各种换法。每行输出一种换法,格式为:“fen5:5分硬币数量, fen2:2分硬币数量, fen1:1分硬币数量, total:硬币总数量”。最后一行输出“count = 换法个数”。
输入样例:
13
结尾无空行
输出样例:
fen5:2, fen2:1, fen1:1, total:4
fen5:1, fen2:3, fen1:2, total:6
fen5:1, fen2:2, fen1:4, total:7
fen5:1, fen2:1, fen1:6, total:8
count = 4
结尾无空行
1.1 分析
- 要求按5分、2分和1分硬币的数量依次从大到小的顺序,所以先找最多有几个5分,由于要求每种硬币至少有一枚,所以从最多可能的个数遍历到只有一个。
- 其中i,j,k表示每个硬币的个数。确定了5分硬币个数后,可以继续确定2分硬币的个数j=(x-i*5)/2。然后确定1分硬币的个数k。
- 最后进行判断,如果所有硬币加起来等于待换的零钱数额,那么输出。
1.2 代码:
#include<stdio.h>
int main(){int x;scanf("%d",&x);int five,sum=0,i,j,k;five=x/5;//找最多有几个5for(i=five;i>=1;--i){for(j=(x-i*5)/2;j>=1;--j){for(k=x-i*5-j*2;k>=1;--k){if(i*5+j*2+k==x){sum++;printf("fen5:%d, fen2:%d, fen1:%d, total:%d\n",i,j,k,i+j+k);}}}}printf("count = %d",sum);
}
2.水仙花数 :
习题4-6 水仙花数 (20 分)
水仙花数是指一个N位正整数(N≥3),它的每个位上的数字的N次幂之和等于它本身。例如:153=13 + 53+33。 本题要求编写程序,计算所有N位水仙花数。
输入格式:
输入在一行中给出一个正整数N(3≤N≤7)。
输出格式:
按递增顺序输出所有N位水仙花数,每个数字占一行。
输入样例:
3
结尾无空行
输出样例:
153
370
371
407
结尾无空行
2.1分析与代码
如果引用math.h头文件中的pow函数,会导致运行超时。
所以需要自己写一个pow函数。
#include<stdio.h>
long long pow(int a,int b){long long sum=1;for(int i=0;i<b;++i){sum=sum*a;}return sum;
}
int main(){int n;scanf("%d",&n);long long begin=pow(10,n-1),end=pow(10,n);long long m,sum=0,i;for(i=begin;i<end;++i){//水仙花数的范围-N位正整数m=i;while(m>0){//对m的每一项进行处理sum+=pow(m%10,n);if(sum>i) break;m=m/10;}if(sum==i) {printf("%d\n",i);}sum=0;}
}
3.最大公约数和最小公倍数:
习题4-7 最大公约数和最小公倍数 (15 分)
本题要求两个给定正整数的最大公约数和最小公倍数。
输入格式:
输入在一行中给出两个正整数M和N(≤1000)。
输出格式:
在一行中顺序输出M和N的最大公约数和最小公倍数,两数字间以1空格分隔。
输入样例:
511 292
结尾无空行
输出样例:
73 2044
结尾无空行
3.1 分析
-
假设现在要求最小公倍数的两个数为x,y,他们的最大公约数为p,最小公倍数为q。则xy=pq
-
最大公约数求法
求最大公约数可以使用辗转相除法:
gcd(a,b) = gcd(b,a mod b) (不妨设a>b 且r=a mod b ,r不为0)
int gg(int a,int b){int c;while(b){c=a;a=b;b=c%b;/*a mod b为零时,由于上面把b给了a,*//*所以此时的a就是最大公约数*/}return a;
}
3.2 代码
#include<stdio.h>
int gg(int a,int b){int c;while(b){c=a;a=b;b=c%b;}return a;
}
int main(){int a,b;scanf("%d %d",&a,&b);int k=gg(a,b);int m=a*b/k;//他们的最大公约数为k,最小公倍数为m。则ab=kmprintf("%d %d",k,m);
}
4.高空坠球
习题4-8 高空坠球 (20 分)
皮球从某给定高度自由落下,触地后反弹到原高度的一半,再落下,再反弹,……,如此反复。问皮球在第n次落地时,在空中一共经过多少距离?第n次反弹的高度是多少?
输入格式:
输入在一行中给出两个非负整数,分别是皮球的初始高度和n,均在长整型范围内。
输出格式:
在一行中顺序输出皮球第n次落地时在空中经过的距离、以及第n次反弹的高度,其间以一个空格分隔,保留一位小数。题目保证计算结果不超过双精度范围。
输入样例:
33 5
结尾无空行
输出样例:
94.9 1.0
4.1分析与代码
从空中到落地,从地面到空中,这是两个过程,不要只加上反弹的距离,还要考虑落地的距离。
第1次落地时,反弹数为0。我在代码中的移动距离为离地距离加上反弹距离,所以最后一次落地时,移动距离要减去第n次反弹的距离。
#include<stdio.h>int main(){double h,n;scanf("%lf %lf",&h,&n);double sum=0,num=0;for(int i=0;i<n;++i){num = h/2;sum+=num+h;//代码中的移动距离为离地距离加上反弹距离h=num;}printf("%.1lf %.1lf",sum-num,num);//移动距离要减去第n次反弹的距离。
}
5.猴子吃桃问题
习题4-10 猴子吃桃问题 (15 分)
一只猴子第一天摘下若干个桃子,当即吃了一半,还不过瘾,又多吃了一个;第二天早上又将剩下的桃子吃掉一半,又多吃了一个。以后每天早上都吃了前一天剩下的一半加一个。到第N天早上想再吃时,见只剩下一个桃子了。问:第一天共摘了多少个桃子?
输入格式:
输入在一行中给出正整数N(1<N≤10)。
输出格式:
在一行中输出第一天共摘了多少个桃子。
输入样例:
3
结尾无空行
输出样例:
10
5.1分析与代码
现在是知道第n天剩的桃求第1天的桃,
第二天的桃子=第一天桃子/2-1
第i天的桃等于(第i+1天的剩的桃+1)*2,因此有:f(i)=(f(i+1)+1)∗2,结束条件是f(n)=1。
#include<stdio.h>
int f(int x,int n){if(x==n) return 1;else return (f(x+1,n)+1)*2;
}
int main(){int n,sum=1;scanf("%d",&n);printf("%d",f(1,n));
}
6.兔子繁衍问题
习题4-11 兔子繁衍问题 (15 分)
一对兔子,从出生后第3个月起每个月都生一对兔子。小兔子长到第3个月后每个月又生一对兔子。假如兔子都不死,请问第1个月出生的一对兔子,至少需要繁衍到第几个月时兔子总数才可以达到N对?
输入格式:
输入在一行中给出一个不超过10000的正整数N。
输出格式:
在一行中输出兔子总数达到N最少需要的月数。
输入样例:
30
结尾无空行
输出样例:
9
6.1分析与代码
f(n)表示n个月后的兔子总数
f(n)=n那个月原有的兔子+n那个月新生的兔子
n那个月原有的兔子是:f(n-1)
由于是第三个月起,小兔子每个月就能生,也就是说小兔子跨到大兔子其实只需要两个月。
n那个月新生的兔子就等于两个月前所有的兔子,因为两个月后,这些兔子都能生了。
也就是说:n那个月新生的兔子=f(n-2)
每个月的兔子总对数可以归纳为一个分段函数:
f(n) = 1 (n=1,2)
f(n) = f(n-1) + f(n-2) (n=3,4,5)
#include<stdio.h>int main(){int n;scanf("%d",&n);int a[100],i;a[1]=a[2]=1;if(n==1){printf("%d",1);return 0;}for(i=3;;i++){a[i]=a[i-1]+a[i-2];if(a[i]>=n) {printf("%d",i);return 0;}}
}
7.出租车计价
习题3-3 出租车计价 (15 分)
本题要求根据某城市普通出租车收费标准编写程序进行车费计算。具体标准如下:
起步里程为3公里,起步费10元;
超起步里程后10公里内,每公里2元;
超过10公里以上的部分加收50%的回空补贴费,即每公里3元;
营运过程中,因路阻及乘客要求临时停车的,按每5分钟2元计收(不足5分钟则不收费)。
输入格式:
输入在一行中给出输入行驶里程(单位为公里,精确到小数点后1位)与等待时间(整数,单位为分钟),其间以空格分隔。
输出格式:
在一行中输出乘客应支付的车费(单位为元),结果四舍五入,保留到元。
输入样例1:
2.6 2
结尾无空行
输出样例1:
10
7.1分析与代码
这个题主要是题意,每5分钟2元计收,六分钟也是两元,因为是每5分钟。所以t要设置为int类型。
#include<stdio.h>int main(){double x;int t;double sum=0;scanf("%lf %d",&x,&t);sum+=10;if(t>=5)sum+=t/5*2;if(x>3){//起步里程于3公里 if(x<=10) //起步里程小于等于10公里{sum+=(x-3)*2;}else{//起步里程大于10公里sum+=7*2+(x-10)*3;}}printf("%.0lf",sum);//四舍五入
}
8.三角形判断
习题3-5 三角形判断 (15 分)
给定平面上任意三个点的坐标,检验它们能否构成三角形。
输入格式:
输入在一行中顺序给出六个[−100,100]范围内的数字,即三个点的坐标
输出格式:
若这3个点不能构成三角形,则在一行中输出“Impossible”;若可以,则在一行中输出该三角形的周长和面积,格式为“L = 周长, A = 面积”,输出到小数点后2位。
输入样例1:
4 5 6 9 7 8
结尾无空行
输出样例1:
L = 10.13, A = 3.00
结尾无空行
输入样例2:
4 6 8 12 12 18
输出样例2:
Impossible
8.1分析与代码
这个题需要知道海伦公式,通过三边长度求得三角形面积。
已知三角形三边a,b,c,(p=(a+b+c)/2)
S=sqrt[p(p-a)(p-b)(p-c)]
=sqrt[(1/16)(a+b+c)(a+b-c)(a+c-b)(b+c-a)]
=1/4sqrt[(a+b+c)(a+b-c)(a+c-b)(b+c-a)]
而且经过测试发现只需要判断两边之和大于第三边,就可以确定它可以构成三角形。
三角形三边关系的定理:“三角形任何两边的和大于第三边”和它的推论:“三角形任何两边的差小于第三边”
进行判断的时候,其实只需要判断最小的两边和大于最长一边即可
#include<stdio.h>
#include<math.h>
int main(){double x1,y1,x2,y2,x3,y3;double l1,l2,l3;double s,c,a;scanf("%lf %lf %lf %lf %lf %lf",&x1,&y1,&x2,&y2,&x3,&y3);l1=sqrt(pow(x1-x2,2)+pow(y1-y2,2));l2=sqrt(pow(x2-x3,2)+pow(y2-y3,2));l3=sqrt(pow(x1-x3,2)+pow(y1-y3,2));if((l1+l2>l3)&&(l2+l3>l1)&&(l1+l3>l2)){//两边之和大于第三边 if((l1-l2<l3)&&(l1-l3<l2)&&(l2-l1<l3)&&(l2-l3<l1)&&(l3-l2<l1)&&(l3-l1<l2)){//两边之差小于第三边,这个可以忽略c=l1+l2+l3;a=c/2;s=sqrt(a*(a-l1)*(a-l2)*(a-l3));printf("L = %.2lf, A = %.2lf",c,s);}}else {printf("Impossible");}
}
9.简单计算器
习题6-7 简单计算器 (20 分)
模拟简单运算器的工作。假设计算器只能进行加减乘除运算,运算数和结果都是整数,四种运算符的优先级相同,按从左到右的顺序计算。
输入格式:
输入在一行中给出一个四则运算算式,没有空格,且至少有一个操作数。遇等号”=”说明输入结束。
输出格式:
在一行中输出算式的运算结果,或者如果除法分母为0或有非法运算符,则输出错误信息“ERROR”。
输入样例:
1+2*10-10/2=
结尾无空行
输出样例:
10
结尾无空行
9.1分析与代码
题意说在一行中给出一个四则运算算式,说明数字和字符是交叉输入的。所以就分别对每次的输入进行判断处理即可。
#include<stdio.h>int main(){int sum;int num;char a;scanf("%d",&sum);while(scanf("%c",&a)&&a!='='){scanf("%d",&num);if(a=='+') sum+=num;else if(a=='-') sum-=num;else if(a=='*') sum=sum*num;else if(a=='/'){if(num==0) {printf("ERROR");return 0;}else{sum=sum/num;}}else{printf("ERROR");return 0;}}printf("%d",sum);
}
10.平面向量加法
习题9-3 平面向量加法 (15 分)
本题要求编写程序,计算两个二维平面向量的和向量。
输入格式:
输入在一行中给出两个二维平面向量的分量。
输出格式:
在一行中按照(x, y)的格式输出和向量,坐标输出小数点后一位(注意不能输出−0.0)。
输入样例:
3.5 -2.7 -13.9 8.7
结尾无空行
输出样例:
(-10.4, 6.0)
结尾无空行
分析与解答
小数部分按指定位数输出,编译器会进行四舍五入处理,如果和的结果是-0.04,输出会是-0.0,而如果绝对值结果是0.05及以上,四舍五入是0.1,有了上面的条件就可以保证 结果不会出现-0.0的情况了。
#include<stdio.h>
#include<string.h>
int main()
{double x1,y1,x2,y2;scanf("%lf %lf %lf %lf",&x1,&y1,&x2,&y2);double a=x1+x2;double b=y1+y2;if(fabs(a)<0.05) a=0.0;if(fabs(b)<0.05) b=0.0;printf("(%.1lf, %.1lf)",a,b);
}