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;
}