中国电子学会(CEIT)2021年06月真题C语言软件编程等级考试三级(含详细解析答案)

发布于:2024-03-31 ⋅ 阅读:(103) ⋅ 点赞:(0)

中国电子学会(CEIT)考评中心历届真题(含解析答案)

C语言软件编程等级考试三级 2021年06月

编程题五道							总分:100分

一、数对(20分)
给定2到15个不同的正整数,你的任务是计算这些数里面有多少个数对满足:数对中一个数是另一个数的两倍。比如给定1 4 3 2 9 7 18 22,得到的答案是3,因为2是1的两倍,4是2个两倍,18是9的两倍。
时间限制: 1000ms
内存限制: 65536kb
输入
一行,给出2到15个两两不同且小于100的正整数。最后用O表示输入结束。
输出
一个整数,即有多少个数对满足其中一个数是另一个数的两倍。
样例输入

1 4 3 2 9 7 18 22 0

样例输出

3
#include<stdio.h> // 引入标准输入输出库

int main() {
    int i,j,n; // 定义循环变量和有效数字个数n
    int m[15],c=0; // 定义长度为15的数组m用于存储输入的数字,并初始化c为0(c用于统计满足条件的数字对数量)

    // 输入数据,统计有效的数字个数n
    for(i=0; i<15; i++){ // 遍历数组m的前15个元素
        scanf("%d",&m[i]); // 从标准输入读取一个整数并存入m[i]
        if(m[i]==0){ // 如果当前元素为0
            n=i; // 则有效数字个数n为当前索引i
            break; // 并跳出循环
        }
    }

    // 枚举所有数据
    for(i=0; i<n-1; i++){ // 外层循环遍历前n-1个有效数字
        for(j=i+1; j<n; j++){ // 内层循环遍历从i+1到n-1的有效数字
            int a=m[i]; // 将m[i]赋值给a
            int b=m[j]; // 将m[j]赋值给b

            // 保证a要比b大,用a/b
            if(a<b){ // 如果a小于b
                int t=a; // 交换a和b的值
                a=b;
                b=t;
            }

            // 判断a是b的两倍
            if(a/b==2 && a%b==0) { // 如果a除以b的商为2且余数为0
                c++; // 则满足条件的数字对数量c增加1
            }
        }
    }

    printf("%d",c); // 输出满足条件的数字对数量c
    return 0; // 程序正常结束
}
/*
	注意:

		如果数组m中第一个元素就是0,那么n将被设置为0,
		并且后面的循环将不会执行。这可能会导致程序逻辑错误。
		在判断a/b==2 && a%b==0时,如果a和b都是非零整数,那么
		a%b==0将始终为真,因为a是b的两倍。因此,a%b==0这个条
		件实际上是多余的。
		如果a和b都是负数,并且a是b的两倍,那么a/b可能会因为整
		数除法而向下取整,导致a/b==2不成立。例如,如果a=-4,b=-2,
		那么a/b将等于-2而不是2。这可能会导致一些满足条件的数字对被遗漏。
	
*/

二、井和绳子(20分)
有A,B, C,D, E五家人共用一口井,已知井深不超过k米。A,B, C , D, E的绳长各不相同,而且厘米表示的绳长一定是整数。
从井口放下绳索正好达到水面时:
(a)需要A家的绳n1条接上B家的绳1条
(b)需要B家的绳n2条接上C家的绳1条
©需要C家的绳n3条接上D家的绳1条
(d)需要D家的绳n4条接上E家的绳1条
(e)需要E家的绳n5条接上A家的绳1条
问井深和各家绳长。
时间限制: 1000ms
内存限制: 65536kb
输入
输入只有1行。包括空格分开的6个整数。第一个整数k (1 <= k <= 20),代表井的最大深度(单位:米)。接下来是5个正整数n1, n2,n3, n4, n5。这五个整数的含义见上面的题目描述。
输出
输出只有1行。如果找到了可行解,就输出6个整数,用空格分开,分别代表井的深度和A,B, C,D, E的绳长(单位都是厘米)。如果有多组可行解,输出井的深度最小的那组解。如果不存在可行解,就输出一行: not found
样例输入

10 2 3 4 5 6

样例输出

721 265 191 148 129 76
#include<stdio.h> // 引入标准输入输出库

int main() {
    int i;		//定义整型变量i 
    int k, len; // k表示井的深度(单位为米),len表示当前枚举的长度
    int a, b, c, d, e; // a, b, c, d, e分别表示五种不同长度的绳子可以拉出的长度
    int n[5]; // n数组存储五种不同绳子的拉伸倍数,例如n[0]表示第一种绳子的拉伸倍数

    // 读取用户输入的井的深度(单位为米)
    scanf("%d" ,&k);
    k *= 100; // 将井的深度转换为厘米,因为绳子拉伸的倍数是以厘米为单位的

    // 读取五种绳子的拉伸倍数
    for(i = 0; i < 5; i++){
        scanf("%d", &n[i]);
    }

    // 使用枚举法枚举井的深度
    for(len = 1; len <= k; len++){ // 枚举a的长度,从1开始到井的最大深度
        for(a = 1; a < len - 1; a++){ // 枚举a的长度,注意a不能是0或len-1,因为b和e的计算需要用到len-a和len-d
            b = len - n[0] * a; // 根据第一种绳子的拉伸倍数和a的长度,计算b的长度
            c = len - n[1] * b; // 根据第二种绳子的拉伸倍数和b的长度,计算c的长度
            d = len - n[2] * c; // 根据第三种绳子的拉伸倍数和c的长度,计算d的长度
            e = len - n[3] * d; // 根据第四种绳子的拉伸倍数和d的长度,计算e的长度

            // 检查是否满足条件:e*n[4] + a == len,即最后一段绳子(e)拉伸后加上第一段绳子(a)的长度等于井的总深度
            if(e * n[4] + a == len) {
                printf("%d %d %d %d %d %d" ,len, a, b, c, d, e); // 如果满足条件,输出结果
                return 0; // 找到解后退出程序
            }
        }
    }
    printf("not found"); // 如果没有找到满足条件的解,输出"not found"
    return 0; // 程序结束
}
/*
	该代码的目的是通过五种不同拉伸倍数的绳子来测量一个井的深度。
	它使用枚举法来尝试所有可能的绳子长度组合,以找到一种组合,
	使得这五种绳子拉伸后的总长度等于井的深度。如果找到了这样的
	组合,就输出这个组合;否则,输出"not found"。
*/

三、爬楼(20分)
已知楼梯的数量,可以每次走2级或者3级,求不同的走法数
例如:楼梯一共有7级,一共3种方法: 2 2 3或者 2 3 2或者 3 2 2。
时间限制: 1000ms
内存限制: 65536kb
输入
输入包含若干行,每行包含一个正整数N,代表楼梯级数,1 <=N <= 50。最后一行为0,表示测试结束。
输出
不同的走法数,每一行输入对应一行输出
样例输入

7
0

样例输出

3
#include <stdio.h> // 引入标准输入输出库,用于scanf和printf函数

// 定义一个函数calculate,用于计算上楼梯的方式数量
int calculate(int n) {
    // 如果只有一个楼梯,那么只有一种方式:不爬
    if (n == 1)
        return 0;
    // 如果有两个楼梯,有两种方式:爬一个楼梯然后跳一个,或者直接跳两个
    else if (n == 2)
        return 1;
    // 如果有三个楼梯,只有一种方式:爬一个楼梯然后跳两个
    else if(n == 3)
        return 1;
    // 对于其他数量的楼梯,使用递归方式计算
    // 上n个楼梯的方式数等于上n-2个楼梯的方式数(跨过一个楼梯)加上上n-3个楼梯的方式数(跨过两个楼梯)
    else
        return calculate(n - 2) + calculate(n - 3);
}

// main函数,程序的入口点
int main() {
    int n; // 定义一个整数变量n,用于存储用户输入的楼梯数量
    int c; // 定义一个整数变量c,用于存储计算出的上楼梯的方式数量
    // 使用一个无限循环,直到用户输入0为止
    while(1) {
        scanf("%d",&n); // 从标准输入读取一个整数,并存储在变量n中
        if(n==0) // 如果用户输入的是0,则跳出循环
            break;
        c=calculate(n); // 调用calculate函数计算上n个楼梯的方式数量,并将结果存储在变量c中
        printf("%d\n",c); // 将计算结果输出到标准输出
    }
    return 0; // 程序正常结束,返回0
}
/*
	这个代码实现了一个递归函数calculate,用于计算上n个楼梯的不同方式数量。
	根据题目描述,每次可以爬1个或2个楼梯,因此上n个楼梯的方式数等于上n-2个
	楼梯的方式数(跨过一个楼梯)加上上n-3个楼梯的方式数(跨过两个楼梯)。
	注意,这个递归实现方式在n较大时可能会导致性能问题,因为它会重复计算很
	多子问题。在实际应用中,可以考虑使用动态规划或其他优化方法来提高性能。
*/

四、表达式求值(20分)
输入一个布尔表达式,请你输出它的真假值。比如:(V|V )&F & ( F|V)
V表示true,F表示false,&表示与,|表示或,!表示非。上式的结果是F
时间限制: 1000
内存限制: 65536
输入
输入包含多行,每行一个布尔表达式,表达式中可以有空格,总长度不超过1000
输出
对每行输入,如果表达式为真,输出"V",否则出来"F"
样例输入

(V |V )&F &( F| V)
!V |V &V & !F & (F|V )&(!F|F | !V & V)
(F&F|V|!V&!F&!(F|F&V))

样例输出

F
v
v
#include<iostream>  // 引入输入输出流库
#include <cstdio>   // 引入C标准输入输出库
#include<algorithm> // 引入算法库(这里虽然没有直接使用到算法库的功能)
#include<queue>     // 引入队列容器
#include <stack>    // 引入栈容器
#include<string>    // 引入字符串处理库
using namespace std; // 使用标准命名空间


// 定义一个函数来计算两个字符('V' 或 'F')之间的逻辑运算
char calculate(char x, char y, char oper){
    bool a = (x == 'V'), b = (y == 'V'), ans;
    if (oper == '|') ans = (a || b);  // 或运算
    else if (oper == '&') ans = (a && b);  // 与运算
    return ans ? 'V' : 'F';  // 返回结果,'V' 代表真,'F' 代表假
}

// 定义一个函数来反转字符 'V' 和 'F'
char reverse(char x){
    if (x == 'V') return 'F';
    return 'V';
}

int main() {
    string in;
    int i, j, len;
    while (getline(cin, in)) {  // 读取输入的表达式
        stack< char > Oper, num;  // Oper 保存运算符,num 保存运算结果
        queue< char > s;  // s 是前缀表达式
        len = in.length();
        i = len;
        in = " " + in;  // 在字符串前面加一个空格,便于处理

        // 从右往左遍历,将中缀表达式转换为前缀表达式
        while (i > 0){
            if (in[i] == ' '){
                i--;
                continue;
            } else if (isalpha(in[i])) s.push(in[i--]);  // 如果是字母,则直接加入前缀表达式
            else if (in[i] == '!') s.push(in[i--]);  // 单目运算符 '!' 直接加入前缀表达式
            else {
                if (in[i] == '&' || in[i] == '|' || in[i] == ')'){  // 如果是低级运算符或右括号
                    Oper.push(in[i--]);  // 压入运算符栈
                } else if (in[i] == '('){  // 如果是左括号
                    while (Oper.top() != ')'){  // 弹出直到遇到右括号
                        s.push(Oper.top());
                        Oper.pop();
                    }
                    Oper.pop();  // 弹出右括号
                    i--;
                }
            }
        }

        // 将运算符栈中剩余的运算符弹出并加入前缀表达式
        while (!Oper.empty()) s.push(Oper.top()), Oper.pop();

        // 计算前缀表达式
        while (!s.empty()){
            char ch = s.front();
            s.pop();

            if (isalpha(ch)) num.push(ch);  // 如果是字母,则加入运算结果栈
            else Oper.push(ch);  // 如果是运算符,则压入运算符栈

            // 如果是单目运算符 '!'
            if (!num.empty() && !Oper.empty() && Oper.top() == '!'){
                char x = num.top();
                num.pop();
                Oper.pop();
                num.push(reverse(x));  // 对结果进行反转
            }

            // 如果是双目运算符
            else if (num.size() >= 2 && !Oper.empty()){
                char oper = Oper.top(), x, y;
                Oper.pop();
                x = num.top();
                num.pop();
                y = num.top();
                num.pop();
                num.push(calculate(x, y, oper));  // 进行计算并将结果压入运算结果栈
            }
        }

        cout << num.top() << endl;  // 输出最终的计算结果
    }
}
/*
	这个代码的核心思路是:
	
	从右往左遍历中缀表达式,将其转换为前缀表达式。
	使用栈来保存运算符,以便处理运算符的优先级。
	计算前缀表达式,得到最终结果。
	这段代码的主要功能是将中缀表达式转换为前缀表达式,
	并计算前缀表达式的值。中缀表达式是我们常见的数学表达式形式,
	例如A & (B | C)。前缀表达式(也称为波兰表示法)是一种将运算
	符放在操作数前面的形式,例如& A | B C。这段代码首先使用中缀
	表达式构建前缀表达式,然后计算前缀表达式的值。
*/

五、数列(20分)
用以下方式构造数列:数列的第一个和第二个数都为1,接下来每个数都等于前面2个数之和。
给出一个正整数a,要求数列中第a个数对1000取模的结果是多少。
时间限制: 1000ms
内存限制: 65536kb
输入
第1行是测试数据的组数n,后面跟着n行输入。每组测试数据占1行,包括一个正整数a(1<=a <= 1000000)。
输出
n行,每行输出对应一个输入。输出应是一个正整数,为数列中第a个数对1000取模得到的结果。
样例输入

4
5
2
19
1

样例输出

5
1
181
1
#include<stdio.h>  // 引入标准输入输出库

// 计算斐波那契数列的第n项
long long fun(int n) {
    if(n == 1)      // 如果n等于1,返回斐波那契数列的第1项,值为1
        return 1;
    if(n == 2)      // 如果n等于2,返回斐波那契数列的第2项,值也为1
        return 1;
    return fun(n-1) + fun(n-2);  // 递归地计算斐波那契数列的第n-1项和第n-2项,并返回它们的和
}

int a[1000];  // 定义一个整数数组a,用于存储用户输入的数值

int main() {
    int i, n;  // 定义循环变量i和用于存储用户输入数量的变量n
    scanf("%d", &n);  // 从标准输入读取一个整数,并存储在变量n中

    for(i = 0; i < n; i++) {  // 使用循环读取用户输入的n个整数
        scanf("%d", &a[i]);  // 从标准输入读取一个整数,并存储在数组a的第i个位置
    }

    for(i = 0; i < n; i++) {  // 使用循环计算并输出每个输入数字对应的斐波那契数列项的模1000结果
        printf("%d\n", fun(a[i]) % 1000);  // 计算斐波那契数列的第a[i]项,并取其对1000的模,然后输出结果
    }

    return 0;  // 程序正常结束,返回0
}

本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到