Bootstrap

2020年09月-电子学会青少年等级考试C语言(二级)真题与解析

2020年09月软件编程(C语言)等级考试(二级)
分数:100   题数:5
时间限制:1000 ms   内存限制:65536 kB

1、单词倒排

【题目描述】
  编写程序,读入一行英文(只包含字母和空格,单词间以单个空格分隔),将所有单词的顺序倒排并输出,依然以单个空格分隔。
【输入】
  输入为一个字符串(字符串长度至多为100)。
【输出】
  输出为按要求排序后的字符串。
【样例输入】
  I am a student
【样例输出】
  student a am I

2、细菌的繁殖与扩散

【题目描述】
  在边长为9的正方形培养皿中,正中心位置有m个细菌。假设细菌的寿命仅一天,但每天可繁殖10个后代,而且这10个后代,有两个分布在原来的单元格中,其余的均匀分布在其四周相邻的八个单元格中。求经过n(1≤n≤4)天后,细菌在培养皿中的分布情况。
【输入】
  输入为两个整数,第一个整数m表示中心位置细菌的个数(2 ≤ m ≤ 30),第二个整数n表示经过的天数(1 ≤ n ≤ 4)。
【输出】
  输出九行九列整数矩阵,每行的整数之间用空格分隔。整个矩阵代表n天后细菌在培养皿上的分布情况。
【样例输入】
  2   1
【样例输出】
  0   0   0   0   0   0   0   0   0
  0   0   0   0   0   0   0   0   0
  0   0   0   0   0   0   0   0   0
  0   0   0   2   2   2   0   0   0
  0   0   0   2   4   2   0   0   0
  0   0   0   2   2   2   0   0   0
  0   0   0   0   0   0   0   0   0
  0   0   0   0   0   0   0   0   0
  0   0   0   0   0   0   0   0   0

3、大整数加法

【题目描述】
  求两个不超过200位的非负整数的和。
【输入】
  有两行,每行是一个不超过200位的非负整数,可能有多余的前导0。
【输出】
  一行,即相加后的结果。结果里不能有多余的前导0,即如果结果是342,那么就不能输出为0342。
【样例输入】
  22222222222222222222
  33333333333333333333
【样例输出】
  55555555555555555555

4、合影效果

【题目描述】
  小云和朋友们去爬香山,为美丽的景色所陶醉,想合影留念。如果他们站成一排,男生全部在左(从拍照者的角度),并按照从矮到高的顺序从左到右排,女生全部在右,并按照从高到矮的顺序从左到右排,请问他们合影的效果是什么样的(所有人的身高都不同)。
【输入】
  第一行是人数n(2 <= n <= 40,且至少有1个男生和1个女生)。 后面紧跟n行,每行输入一个人的性别(男male或女female)和身高(浮点数,单位米),两个数据之间以空格分隔。
【输出】
  n个浮点数,模拟站好队后,拍照者眼中从左到右每个人的身高。每个浮点数需保留到小数点后2位,相邻两个数之间用单个空格隔开。
【样例输入】
  6
  male   1.72
  male   1.78
  female   1.61
  male   1.65
  female   1.70
  female   1.56
【样例输出】
  1.65   1.72   1.78   1.70   1.61   1.56

5、循环数

【题目描述】
  若一个n位的数字串满足下述条件,则称其是循环数(cyclic):将这个数字串视为整数(可能带有前导0),并用任意一个 1 到 n 之间(包含1和n)的整数去乘它时, 会得到一个将原数字串首尾相接后,再在某处断开而得到的新数字串所对应的整数。
  例如,数字 142857 是循环数,因为:
    142857 * 1 = 142857
    142857 * 2 = 285714
    142857 * 3 = 428571
    142857 * 4 = 571428
    142857 * 5 = 714285
    142857 * 6 = 857142
  请写一个程序判断给定的数是否是循环数。
  注意:在此题中,输入数字串允许带前导0,且前导0不能被忽略,例如“01”是两位数字串,而“1”是一位数字串。但将数字串转化为整数做乘法运算或比较运算时,可以忽略前导0。
【输入】
  一行,一个长度在 2 到 60 位之间的数字串。
【输出】
  一个整数,若输入的数字串是循环数,输出1,否则输出0。
【样例输入】
  142857
【样例输出】
  1



2020年09月软件编程(C语言)等级考试(二级)- 题解

1、单词倒排

【参考程序】

#include<bits/stdc++.h>
using namespace std;
char a[105]; //保存输入的字符串
char b[105][105]; //将所有的单词依次保存到二维数组中
int main() {
	int i = 0, lenb = 0, k = 0;//lenb表示字符串中的单词数量
	cin.getline(a, 105); //字符串输入
	for(int i = 0; a[i] != '\0'; i++) { //遍历字符串
		if(a[i] != ' ') { //如果不是空格,表示一个单词还未结束
			b[lenb][k++] = a[i]; //将该单词的每个字符保存到数组b的第lenb项
		} else { //如果是空格,即为一个单词的结束
			lenb++; //下一个单词
			k = 0; //列下标归0
		}
	}
	lenb++; //处理最后一个单词
	//逆序输出
	for(int i = lenb - 1; i >= 0; i--)
	cout << b[i] << " ";
	return 0;
}

2、细菌的繁殖与扩散

【解析】
  此题有两种实现方法。
 【解析1:对应参考程序1】
  ​ 定义两个二维数组,一个用来储存上一天的数据(旧),一个用来计算并保存这一天的数据(新)。而这一天的数据又可以保存到旧数据中,用于下一天的计算(迭代的思想)。
   首先,在原位置上的每1个细菌都可以繁殖10个细菌,其中2个保留在原先的位置,其余8个在周围的8个格子中各1个;然后原来的细菌寿命到了,死亡。
​   这样,我们先把上一天的数据保存在旧数据矩阵中,然后将每个数据都乘以2放到新数据的矩阵中,这是第一次循环。然后再进行一次循环,寻找旧数据矩阵的数据不为零的位置,便在新数据矩阵对应位置的周围八个格子都加上该数据,这一步就相当于细菌在周围单元格中的扩散。这样我们就完成了迭代过程。
​   在计算某一位置的新生细菌数量时,有两种方式:
​   ​  方法1:依次遍历9 * 9正方形培养皿中,找到有细菌的培养皿,基于此培养皿进行细菌繁殖和扩散至周围培养皿。
​   ​  方法2:在经过一天的繁殖后,每一个培养皿中的细菌数量有两部分组成:① 本培养皿中细菌的数量 * 2;② 其周围培养皿进行扩散的数量,也就是周围八个培养皿中的细菌数量。故可以找到通项公式。
​   注意:只能进行四天(循环迭代四次),否则可能出现堆栈错误。此外,数组开的稍大一些,防止在计算周围培养皿数据时发生越界。

 【解析2:对应参考程序2】
   采用三维数组,第一维表示迭代天数,二、三维表示培养皿方格,其余思路同分析1。

【参考程序1】

#include<bits/stdc++.h>
using namespace std;
//旧的培养皿和新的培养皿,用于迭代,定义为全局可自动初始化为0
int old[12][12], birth[12][12];
int main() {
	int m, n;//初始中央细菌数以及迭代的天数
	int i, j, p;
	cin >> m >> n;

	old[5][5] = m; //旧的培养皿正中心位置有 m 个细菌

	for (p = 1; p <= n; p++) { //开始迭代
		for (i = 1; i <= 9; i++) {
			for (j = 1; j <= 9; j++) {
				//方式1:若旧培养皿上某位置有细菌,就在新培养皿上其周围繁殖出细菌(每个细菌各繁殖一圈)
				if (old[i][j] != 0) {
					birth[i][j] = birth[i][j] + 2 * old[i][j]; //两个细菌在本培养皿
                    //其余8个均匀分布在周围培养皿
					birth[i - 1][j - 1] = birth[i - 1][j - 1] + old[i][j];
					birth[i - 1][j] = birth[i - 1][j] + old[i][j];
					birth[i - 1][j + 1] = birth[i - 1][j + 1] + old[i][j];
					birth[i][j - 1] = birth[i][j - 1] + old[i][j];
					birth[i][j + 1] = birth[i][j + 1] + old[i][j];
					birth[i + 1][j - 1] = birth[i + 1][j - 1] + old[i][j];
					birth[i + 1][j] = birth[i + 1][j] + old[i][j];
					birth[i + 1][j + 1] = birth[i + 1][j + 1] + old[i][j];
				}
                //或将以上if语句块换为方式2通项公式
                /*
                	birth[i][j] = 2 * old[i][j] + old[i - 1][j - 1] + old[i][j - 1] + old[i + 1][j - 1] + old[i - 1][j] + old[i + 1][j] + old[i - 1][j + 1] + old[i][j + 1] + old[i + 1][j + 1];
                */
			}
		}

		for (i = 1; i <= 9; i++) {
			for (j = 1; j <= 9; j++) {
				old[i][j] = birth[i][j]; //旧培养皿相当于一个储存容器,储存上一天的培养皿情况
				birth[i][j] = 0;//新的变旧的,凋亡
			}
		}
	}

	//迭代结束,输出培养皿中数据
	for (i = 1; i <= 9; i++) {
		for (j = 1; j <= 9; j++)
			cout << old[i][j] << " ";
		cout << endl;
	}
	return 0;
}

【参考程序2】

#include<bits/stdc++.h>
using namespace std;
//定义三维数组,第一维表示迭代天数,二、三维表示培养皿方格 
int a[5][12][12];
int main() {
	int m, n;//初始中央细菌数以及天数
	int i, j, p;
	cin >> m >> n;

	a[0][5][5] = m; //初始时培养皿正中心有 m 个细菌

	for (p = 1; p <= n; p++) 
		for (i = 1; i <= 9; i++) 
			for (j = 1; j <= 9; j++) 
				a[p][i][j] = 2 * a[p - 1][i][j] + a[p - 1][i - 1][j - 1] + a[p - 1][i][j - 1] + a[p - 1][i + 1][j - 1] + a[p - 1][i - 1][j] + a[p - 1][i + 1][j] + a[p - 1][i - 1][j + 1] + a[p - 1][i][j + 1] + a[p - 1][i + 1][j + 1];

	//输出培养皿中数据
	for (i = 1; i <= 9; i++) {
		for (j = 1; j <= 9; j++)
			cout << a[n][i][j] << " ";
		cout << endl;
	}
	return 0;
}

3、大整数加法

【参考程序】

#include<bits/stdc++.h>
using namespace std;
char s1[205], s2[205];
int a[205], b[205], c[205];
int main() {
	cin >> s1 >> s2; //输入两个整数的字符串类型
	int lena = strlen(s1), lenb = strlen(s2); //计算两字符串长度

	//将字符数组逆序存放到整数数组中
	for(int i = 0; i < lena; i++)	 
        a[i] = s1[lena - i - 1] - '0'; //或 a[i] = s1[len1-i-1] - 48;
	for(int i = 0; i < lenb; i++)	 
        b[i] = s2[lenb - i - 1] - '0'; //或 b[i] = s2[len2-i-1] - 48;

	int r = 0, lenc = 0; //r表示进位,lenc是计算结果的位数
	for(lenc = 0; lenc < lena || lenc < lenb; lenc++) {
		c[lenc] = a[lenc] + b[lenc] + r;
		r = c[lenc] / 10;  //进位
		c[lenc] %= 10;    //进位后此位上的数字
	}
	c[lenc] = r; //最高位进位

	while(c[lenc] == 0)   //去除前导0
        lenc--; 

	for(int i = lenc; i >= 0; i--)  //逆序输出
		cout << c[i];

	return 0;
}

4、合影效果

【参考程序】

#include<bits/stdc++.h>
using namespace std;

double male[40], female[40]; //分别保存男、女生身高 

bool cmp(double a, double b) { //降序排序 
	return a > b;
}

int main() {
	int n, a = 0, b = 0;  //a、b分别表示男、女生人数 
	char gender[10];  //输入的性别 
	double height;    //输入的身高 
	
	cin >> n;
	for(int i = 0; i < n; i++) {
		cin >> gender >> height;
		if(strcmp(gender, "male") == 0)     //若为男性,将身高存入male数组 
			male[a++] = height;
		else								//否则存入female数组 
			female[b++] = height;
	}
	
	sort(male, male + a);  //male数组升序排序 
	sort(female, female + b, cmp);  //female数组降序排序 
	
	for(int i = 0; i < a; i++)    //先输出male数组 
		printf("%.2f ",male[i]);
	for(int i = 0; i < b; i++)	  //再输出female数组 
		printf("%.2f ",female[i]);
	return 0;
}

5、循环数

【解析】
  解题思路:本题可看作高精度乘法题,用一个二维字符数组 num[][],其中 num[0] 来存放原数,num[i] (1 <= i <= n-1) 分别来存放 num[0] 向左循环移动 i 位的数。然后用原数num[0]去乘以 i (1 <= i <= N),从 num[][]数组中看能否找到相匹配的数串。
  如果有一项不满足,则该数不是循环数。否则则是循环数。
【参考程序】

#include <bits/stdc++.h>
using namespace std;

char num[65][65]; //保存输入的字符串 
int a[65], b[65]; //a:原数逆序数组,b:每次相乘之后的逆序数组 
char c[65];   //b数组逆序后的字符数组 

int main() {
	cin >> num[0]; //输入字符串
	int n = strlen(num[0]);

	//将原数num[0]循环左移 i 位的数存放到num[i]中
	for(int i = 1; i < n; ++i) {
		char t = num[i - 1][0]; //保存上一个数的首位
		for(int j = 0; j < n - 1; ++j)  //循环左移
			num[i][j] = num[i - 1][j + 1];
		num[i][n - 1] = t; //首位放置新数的最后
	}

	for(int i = 0; i < n; i++)
		a[i] = num[0][n - i - 1] - '0'; //字符数组逆序保存到整数数组

	int flag1 = 1;
	for(int i = 2; i <= n; i++) {
		//高精度乘法
		memset(c, 0, sizeof(c));
		int r = 0, lenb;
		for(lenb = 0; lenb < n; lenb++) {
			b[lenb] = a[lenb] * i + r;
			r = b[lenb] / 10;
			b[lenb] %= 10;
		}
		while(r != 0) {
			b[lenb] = r % 10;
			r /= 10;
			lenb++;
		}

		while(b[lenb] == 0) lenb--; //清除前导0

		for(int j = lenb; j >= 0; j--)  //把逆序计算后的结果再逆序,变成正确顺序的字符数组形式 
			c[lenb - j] = b[j] + '0';
		
		//在num[][]数组中看能否找到相匹配的数串
		int flag2 = 0;
		for(int i = 0; i < n; i++) {
			if(strcmp(c, num[i]) == 0) {
				flag2 = 1;
				break;
			}
		}
		if(flag2 == 0) {
			flag1 = 0; //num[][]数组没有匹配的数串
			break;
		}
	}
	cout << flag1;  // cout << (flag1 == 1 ? 1 : 0);
	return 0;
}
;