听说下周开始就有线下课了,我个人还是比较期待的,希望疫情影响早日结束(拜
现在看看这周的题目吧
上机实验
4-15 找完数
本题要求编写程序,找出任意两正整数m和n之间的所有完数。所谓完数就是该数恰好等于除自身外的因子之和。例如:6=1+2+3,其中1、2、3为6的因子。
输入格式:
输入在一行中给出2个正整数m和n(1<m≤n≤10000),中间以空格分隔。
输出格式:
逐行输出给定范围内每个完数的因子累加形式的分解式,每个完数占一行,格式为“完数 = 因子1 + 因子2 + ... + 因子k”,其中完数和因子均按递增顺序给出。若区间内没有完数,则输出“None”。
输入样例:
2 30
输出样例:
6 = 1 + 2 + 3
28 = 1 + 2 + 4 + 7 + 14
完…完数?这是啥?
除自身外的因子之和……好像得找因子,看例子的话,因子应该是指这个数的因数
找因数我们之前有试过找最大公因数,找到全部因数也不麻烦。
那这道题的解题思路也比较简单了,先找到数 n 的所有因数,再全部加起来,判断就行了
(不过好像可以用查找的方法,保存一份完数表,要查询的数直接遍历表,就能简单实现。但这道题显然不是想让我们这么做
代码如下:
#include <stdio.h>
int FindFullNum(int num);
void PrintFullNum(int num);
int main()
{
int numMin, numMax;
scanf("%d%d", &numMin, &numMax);
for (int i = numMin; i <= numMax; i++)
{
if(FindFullNum(i))
{
PrintFullNum(i);
}
}
return 0;
}
int FindFullNum(int num)
{
int sum = 0;
for (int i = 1; i < num; i++)
{
if(num % i == 0)
{
sum += i;
}
}
if(sum == num)
{
return 1;
}
else
{
return 0;
}
}
void PrintFullNum(int num)
{
printf("%d = ", num);
for (int i = 1; i < num; i++)
{
if(num % i == 0)
{
printf("%d + ", i);
}
}
printf("\b\b \n");
}
可能看起来有点多,因为我在这里用了自定义函数,占篇幅会更多一些,但是结构会更清楚一些
(要不咱给每个函数加个注释?
注意最后一句的 "\b\b \n" 是有两个空格的,这是为了将最后的 '+' 给擦除。
4-16 求e的近似值
本题要求编写程序,计算自然常数 e。e 可以用级数 1+1/1!+1/2!+⋯+1/n!+⋯ 来近似计算。本题要求对给定的非负整数 n,求该级数的前 n+1项和。
输入格式:
输入第一行中给出非负整数 n(≤1000)。
输出格式:
在一行中输出部分和的值,保留小数点后八位。
输入样例:
10
输出样例
2.71828180
又是阶乘,上周的手下败将罢了(doge
这题直接嵌套两个循环就可以,不过我们来试试写自定义函数实现
代码如下:
#include <stdio.h>
float OnePartFacN(int num);
int main()
{
int num;
float sum = 1;
scanf("%d", &num);
for (int i = 1; i <= num; i++)
{
sum += OnePartFacN(i);
}
printf("%.8f", sum);
return 0;
}
/**
* @brief 计算N分之一的阶乘
*
* @param num
* @return float
*/
float OnePartFacN(int num)
{
float sum = 1;
for (int i = 1; i <= num; i++)
{
sum *= 1 / (float)i;
}
return sum;
}
代码有了注释就有了灵魂(确信
4-17 作品评分
本题要求编写程序,全国中小学生Scratch作品大赛拉开了序幕。每个参赛选手可以通过网络直接上传作品。本次比赛人人可做评委。每个网络评委可以通过网络对每一件作品进行打分。评分系统也是请程序高手设计的,能自动去掉一个最高分和一个最低分,求出平均分。
输入格式:
输入数据包括两行: 第一行为n,表示n个评委,n>2。第二行是n个评委的打分,分数之间有一个空格。打分是可以带有小数部分的。
输出格式:
输出平均分,结果保留两位小数。
输入样例:
6
10 9 8 7.9 9 9.5
输出样例:
8.8
哇哦,Scratch作品大赛。真羡慕城里人(
咳咳,言归正传,这一题有点麻烦。最难的地方不在排序,而在如何分配内存,让这些不定长输入的评分都能存进计算机内。
可能你会疑惑了,不定长的输入我们之前不是做过几次了吗,为什么会在这里才遇到这种问题呢?
因为之前几次虽然是不定长输入,但是都是只需要保存一个值就够了,而现在的情况是所有值都要保存,这要么要用数组,要么得用指针,但这显然我们都没学过。
果然是像题目中说的,是 “请程序高手设计的” ?
………思考中………
仔细一想,我们并不需要每个值都单独存起来,所以并不需要考虑如何分配内存,一股脑全部加起来然后减去最大和最小就好了!(妙极了
所以代码如下:
#include <stdio.h>
float maxNum(float a, float b);
float minNum(float a, float b);
int main()
{
int num;
float val, sum = 0, max = 0, min = 10;
scanf("%d", &num);
for (int i = 0; i < num; i++)
{
scanf("%f", &val);
sum += val;
max = maxNum(max, val);
min = minNum(min, val);
}
printf("%.2f", (sum - max - min) / (num - 2));
return 0;
}
/**
* @brief 返回两个数的最大值
*
* @param a
* @param b
* @return float
*/
float maxNum(float a, float b)
{
if(a > b)
return a;
else
return b;
}
/**
* @brief 返回两个数的最小值
*
* @param a
* @param b
* @return float
*/
float minNum(float a, float b)
{
if(a > b)
return b;
else
return a;
}
4-18 特殊a串数列求和
本题要求编写程序,给定两个均不超过9的正整数a和n,要求编写程序求a+aa+aaa++⋯+aa⋯a(n个a)之和。
输入格式:
输入在一行中给出不超过9的正整数a和n。
输出格式:
在一行中按照“s = 对应的和”的格式输出。
输入样例:
2 3
输出样例:
s = 246
这个是生成类似 2 22 222这样的数,比较简单
直接看代码:
#include <stdio.h>
#include <math.h>
int CyclesNum(int a, int b);
int main()
{
int num, powNum, sum = 0;
scanf("%d%d", &num, &powNum);
for (int i = 0; i < powNum; i++)
{
sum += CyclesNum(num, i + 1);
}
printf("s = %d", sum);
return 0;
}
/**
* @brief 生成循环数
*
* @param a
* @param b
* @return int
* @example 222 == CyclesNum(2, 3);
*/
int CyclesNum(int a, int b)
{
int sum = 0;
for (int i = 0; i < b; i++)
{
sum += a * (int)pow(10, i);
}
return sum;
}
4-19 打印菱形图案
本题要求编写程序,打印一个高度为n的、由“*”组成的正菱形图案。
输入格式:
输入在一行中给出一个正的奇数n。
输出格式:
输出由n行星号“*”组成的菱形,如样例所示。每个星号后跟一个空格。
输入样例:
7
输出样例:
*
* * *
* * * * *
* * * * * * *
* * * * *
* * *
*
这题思路很多,我这里用一种比较简单的思路
首先输入 n,循环 n 次,每次循环的时候嵌套 n 次的循环。在第 i 行的时候,从(n + 1)/ 2 - i 开始打印 2i - 1 个 ‘*’,其余的打印空格就可以,这样可以打印完上面的三角形;下面的三角形只需要将 i 改为 (n - i)就可以了
代码如下:
#include <stdio.h>
int main()
{
int num;
scanf("%d", &num);
for (int i = 1; i <= num; i++)
{
for (int j = 1; j <= num; j++)
{
if(i <= (num + 1) / 2)
{
if (j > (num + 1) / 2 - i && j <= (num + 1) / 2 + i - 1)
printf("*");
else
printf(" ");
}
else
{
if (j >= (num + 1) / 2 - (num - i) && j <= (num + 1) / 2 + (num - i))
printf("*");
else
printf(" ");
}
}
printf("\n");
}
return 0;
}
4-20 打印九九口诀表
本题要求对任意给定的一位正整数N
,输出从1*1
到N*N
的部分口诀表。
输入格式:
输入在一行中给出一个正整数N
(1≤N
≤9)。
输出格式:
输出下三角N*N
部分口诀表,其中等号右边数字占4位、左对齐。
输入样例:
4
输出样例:
1*1=1
1*2=2 2*2=4
1*3=3 2*3=6 3*3=9
1*4=4 2*4=8 3*4=12 4*4=16
拜托,打印一个九九乘法表超酷的好不好!
言归正传,这个表还是很简单的,比上面打印菱形简单,直接看代码吧
#include <stdio.h>
int main()
{
int num;
scanf("%d", &num);
for (int i = 1; i <= num; i++)
{
for (int j = 1; j <= i; j++)
{
printf("%d * %d = %d\t", i, j, i * j);
}
printf("\n");
}
return 0;
}
4-21 素数和
本题要求编写程序,现在,给定两个整数n和m,0<n<=m<=200,计算第n个素数到第m个素数之间所有的素数的和,包括第n个素数和第m个素数。我们认为2是第一个素数,3是第二个素数,5是第三个素数,依次类推。
输入格式:
两个整数,第一个表示n,第二个表示m。
输出格式:
一个整数,表示第n个素数到第m个素数之间所有的素数的和,包括第n个素数和第m个素数。
输入样例:
2 4
输出样例:
15
啊?素数和?查表就行了(bushi
言归正传,查素数咱之前有做过,就从2开始取模判断就好了。直接看代码吧:
#include <stdio.h>
int IsPrimeNum(int num);
int main()
{
int num = 0, min, max, sum = 0;
scanf("%d%d", &min, &max);
for (int i = 2;; i++)
{
if (IsPrimeNum(i))
{
num++;
if (num >= min && num <= max)
{
sum += i;
}
else if (num > max)
{
break;
}
}
}
printf("%d", sum);
return 0;
}
/**
* @brief 判断传入的数是否为素数
*
* @param num
* @return int / bool
*/
int IsPrimeNum(int num)
{
for (int i = 2; i < num; i++)
{
if (num % i == 0)
return 0;
}
return 1;
}
4-22 念数字
输入一个整数,输出每个数字对应的拼音。当整数为负数时,先输出fu
字。十个数字对应的拼音如下:
0: ling
1: yi
2: er
3: san
4: si
5: wu
6: liu
7: qi
8: ba
9: jiu
输入格式:
输入在一行中给出一个整数,如:1234
。
提示:整数包括负数、零和正数。
输出格式:
在一行中输出这个整数对应的拼音,每个数字的拼音之间用空格分开,行末没有最后的空格。如 yi er san si
。
输入样例:
-600
输出样例:
fuliu ling ling
行末没有空格…好麻烦,这样一来就得增加判断了
这一题主要是要将数字转化成字符,倒也不难,switch就可以
直接看代码吧:
#include <stdio.h>
#include <math.h>
int PrintNumString(int num);
int NumOrder(int num);
int SingleNum(int num, int No);
int main()
{
int num;
scanf("%d", &num);
if (num < 0)
{
printf("fu");
num *= -1;
}
for (int i = NumOrder(num); i > 0; i--)
{
PrintNumString(SingleNum(num, i));
if(i != 1)
printf(" ");
}
return 0;
}
/**
* @brief 判断输入数的数量级
*
* @param num
* @return int
* @example 3 == NumOrder(200)
*/
int NumOrder(int num)
{
int order = 0;
for (int i = 0;; i++)
{
if (num / (int)pow(10, i))
order++;
else
break;
}
return order;
}
/**
* @brief 取出单个数
*
* @param num 输入数
* @param No 位数
* @return int
* @example 3 == SingleNum(123, 1);
*/
int SingleNum(int num, int No)
{
num /= pow(10, No - 1);
return num % 10;
}
/**
* @brief 打印数字对应的字符串
*
* @param num
* @return int
*/
int PrintNumString(int num)
{
switch (num)
{
case 0:
printf("lin");
break;
case 1:
printf("yi");
break;
case 2:
printf("er");
break;
case 3:
printf("san");
break;
case 4:
printf("si");
break;
case 5:
printf("wu");
break;
case 6:
printf("liu");
break;
case 7:
printf("qi");
break;
case 8:
printf("ba");
break;
case 9:
printf("jiu");
break;
default:
break;
}
}
代码看着很唬人,其实只用看main里面就行
结语
最近的作业渐渐麻烦起来了
这周的代码开始尽可能将部分功能作为函数独立出来,这样以后需要的话直接复制过去就行,非常方便;而且在看代码的时候结构也更加清晰,只看函数名就知道功能
虽然一看上去代码量多了不少,十几行能完成的愣是写成了几十行,但这是模块化的代价,能接受。看代码的时候并不需要完全看完,只看main也能了解整体思路