2023年09月 C/C++(五级)真题解析#中国电子学会#全国青少年软件编程等级考试

2023年09月 C/C++(五级)真题解析#中国电子学会#全国青少年软件编程等级考试_第1张图片

C/C++编程(1~8级)全部真题・点这里
Python编程(1~6级)全部真题・点这里

第1题:红与黑

有一间长方形的房子,地上铺了红色、黑色两种颜色的正方形瓷砖。你站在其中一块黑色的瓷砖上,只能向相邻的黑色瓷砖移动。请写一个程序,计算你总共能够到达多少块黑色的瓷砖。
时间限制:1000
内存限制:65536
输入
包括多个数据集合。每个数据集合的第一行是两个整数W和H,分别表示x方向和y方向瓷砖的数量。W和H都不超过20。在接下来的H行中,每行包括W个字符。每个字符表示一块瓷砖的颜色,规则如下 1)‘.’:黑色的瓷砖; 2)‘#’:白色的瓷砖; 3)‘@’:黑色的瓷砖,并且你站在这块瓷砖上。该字符在每个数据集合中唯一出现一次。 当在一行中读入的是两个零时,表示输入结束。
输出
对每个数据集合,分别输出一行,显示你从初始位置出发能到达的瓷砖数(记数时包括初始位置的瓷砖)。
样例输入
6 9
…#.
…#





#@…#
.#…#.
0 0
样例输出
45

以下是使用C语言编写的解决方案:

#include 

int W, H;  // 瓷砖的宽度和高度
char tiles[20][20];  // 存储瓷砖颜色的数组
int visited[20][20];  // 记录是否访问过的数组
int count;  // 记录能到达的瓷砖数量

void dfs(int x, int y) {
    if (x < 0 || x >= W || y < 0 || y >= H || visited[y][x] || tiles[y][x] == '#') {
        return;  // 越界或已访问过或是白色瓷砖,返回
    }

    visited[y][x] = 1;  // 标记为已访问
    count++;  // 计数加一

    // 继续搜索相邻的黑色瓷砖
    dfs(x - 1, y);
    dfs(x + 1, y);
    dfs(x, y - 1);
    dfs(x, y + 1);
}

int main() {
    while (1) {
        scanf("%d %d", &W, &H);
        if (W == 0 && H == 0) {
            break;  // 输入结束
        }

        int startX, startY;  // 初始位置坐标
        for (int i = 0; i < H; i++) {
            scanf("%s", tiles[i]);
            for (int j = 0; j < W; j++) {
                visited[i][j] = 0;  // 初始化visited数组
                if (tiles[i][j] == '@') {
                    startX = j;
                    startY = i;  // 记录初始位置坐标
                }
            }
        }

        count = 0;  // 初始化计数器
        dfs(startX, startY);  // 深度优先搜索

        printf("%d\n", count);
    }

    return 0;
}

你可以将以上代码保存为一个名为tiles.c的文件,然后使用C编译器进行编译和执行。

程序使用一个递归的深度优先搜索(DFS)算法来计算能够到达的瓷砖数量。

在主函数中,使用一个无限循环,每次循环读取一个数据集合的瓷砖宽度W和高度H。

如果输入的瓷砖宽度和高度都为零,则表示输入结束,跳出循环。

在每个数据集合中,使用一个嵌套循环读取瓷砖颜色,并初始化visited数组。

同时,记录初始位置坐标。

然后,初始化计数器count为0,调用dfs函数进行深度优先搜索。

在dfs函数中,首先判断当前位置是否越界、是否已访问过或是否是白色瓷砖,如果是,则返回。

将当前位置标记为已访问,计数器加一。

然后,递归地搜索相邻的黑色瓷砖,即上、下、左、右四个方向。

最后,在主函数中,使用printf函数输出计算得到的结果。

例如,如果输入为:

6 9
....#.
.....#
......
......
......
......
......
#@...#
.#..#.
0 0

表示有一个数据集合,瓷砖宽度为6,高度为9。

瓷砖颜色如下所示:

....#.
.....#
......
......
......
......
......
#@...#
.#..#.

其中,'.‘表示黑色瓷砖,’#‘表示白色瓷砖,’@'表示你站在的初始位置。

程序将计算能够到达的瓷砖数量,并输出。

根据给定的数据,能够到达的瓷砖数量为45,输出"45"。

第2题:装箱问题

一个工厂制造的产品形状都是长方体,它们的高度都是h,长和宽都相等,一共有六个型号,他们的长宽分别为11, 22, 33, 44, 55, 66。这些产品通常使用一个 66h 的长方体包裹包装然后邮寄给客户。因为邮费很贵,所以工厂要想方设法的减小每个订单运送时的包裹数量。他们很需要有一个好的程序帮他们解决这个问题从而节省费用。现在这个程序由你来设计。
时间限制:1000
内存限制:65536
输入
输入文件包括几行,每一行代表一个订单。每个订单里的一行包括六个整数,中间用空格隔开,分别为11至66这六种产品的数量。输入文件将以6个0组成的一行结尾。
输出
除了输入的最后一行6个0以外,输入文件里每一行对应着输出文件的一行,每一行输出一个整数代表对应的订单所需的最小包裹数。
样例输入
0 0 4 0 0 1
7 5 1 0 0 0
0 0 0 0 0 0
样例输出
2
1

以下是使用C语言编写的解决方案:

#include 

int main() {
    int counts[6];  // 存储每种产品的数量
    int i, j, k;  // 循环变量
    int packages;  // 记录需要的包裹数量

    while (1) {
        // 读取订单中每种产品的数量
        for (i = 0; i < 6; i++) {
            scanf("%d", &counts[i]);
        }

        // 检查是否输入了六个0,如果是则结束程序
        if (counts[0] == 0 && counts[1] == 0 && counts[2] == 0 &&
            counts[3] == 0 && counts[4] == 0 && counts[5] == 0) {
            break;
        }

        packages = 0;  // 初始化包裹数量为0

        // 尝试将产品装入已有的包裹中
        while (counts[5] > 0) {
            packages++;  // 使用一个新的包裹
            counts[5]--;  // 将一个6*6的产品放入包裹
        }

        // 尝试将5*5的产品装入已有的包裹中
        while (counts[4] > 0) {
            packages++;  // 使用一个新的包裹
            counts[4]--;  // 将一个5*5的产品放入包裹

            // 尝试将1*1的产品填满剩余的空间
            for (i = 0; i < 11 && counts[0] > 0; i++) {
                counts[0]--;  // 将一个1*1的产品放入包裹
            }
        }

        // 尝试将4*4的产品装入已有的包裹中
        while (counts[3] > 0) {
            packages++;  // 使用一个新的包裹
            counts[3]--;  // 将一个4*4的产品放入包裹

            // 尝试将2*2的产品填满剩余的空间
            for (i = 0; i < 5 && counts[1] > 0; i++) {
                counts[1]--;  // 将一个2*2的产品放入包裹
            }

            // 尝试将1*1的产品填满剩余的空间
            for (i = 0; i < 20 && counts[0] > 0; i++) {
                counts[0]--;  // 将一个1*1的产品放入包裹
            }
        }

        // 尝试将3*3的产品装入已有的包裹中
        while (counts[2] > 0) {
            packages++;  // 使用一个新的包裹
            counts[2]--;  // 将一个3*3的产品放入包裹

            // 尝试将2*2的产品填满剩余的空间
            for (i = 0; i < 9 && counts[1] > 0; i++) {
                counts[1]--;  // 将一个2*2的产品放入包裹
            }

            // 尝试将1*1的产品填满剩余的空间
            for (i = 0; i < 36 && counts[0] > 0; i++) {
                counts[0]--;  // 将一个1*1的产品放入包裹
            }
        }

        // 将剩余的2*2的产品装入已有的包裹中
        while (counts[1] > 0) {
            packages++;  // 使用一个新的包裹
            counts[1]--;  // 将一个2*2的产品放入包裹

            // 尝试将1*1的产品填满剩余的空间
            for (i = 0; i < 64 && counts[0] > 0; i++) {
                counts[0]--;  // 将一个1*1的产品放入包裹
            }
        }

        // 将剩余的1*1的产品装入已有的包裹中
        while (counts[0] > 0) {
            packages++;  // 使用一个新的包裹
            counts[0]--;  // 将一个1*1的产品放入包裹
        }

        printf("%d\n", packages);  // 输出需要的包裹数量
    }

    return 0;
}

程序通过逐个检查每种产品的数量,从大到小尝试将它们装入包裹中,以尽量减少包裹的数量。

首先,使用一个无限循环读取每个订单的产品数量,存储在一个整数数组counts中。

如果输入的订单中六种产品的数量都为零,则表示输入结束,跳出循环。

然后,初始化包裹数量packages为0。

接下来,使用循环尝试将不同大小的产品装入已有的包裹中,从大到小依次尝试。

对于6*6的产品,直接使用一个新的包裹。

对于55的产品,先使用一个新的包裹放入55的产品,然后尝试将剩余的空间填满。

对于44的产品,先使用一个新的包裹放入44的产品,然后尝试将剩余的空间填满。

对于33的产品,先使用一个新的包裹放入33的产品,然后尝试将剩余的空间填满。

对于22的产品,先使用一个新的包裹放入22的产品,然后尝试将剩余的空间填满。

对于1*1的产品,直接使用一个新的包裹。

最后,在每个订单结束后,使用printf函数输出需要的包裹数量。

例如,如果输入为:

0 0 4 0 0 1
7 5 1 0 0 0
0 0 0 0 0 0

表示有两个订单。

第一个订单中,4个33的产品和1个11的产品。

第二个订单中,7个11的产品,5个22的产品和1个3*3的产品。

程序将计算每个订单所需的最小包裹数,并输出。

根据给定的数据,第一个订单需要2个包裹,第二个订单需要1个包裹,输出为:

2
1

第3题:课程表

现在你总共有n门课需要选,记为0到n-1。在选修某些课程之前需要一些先修课程。例如,想要学习课程0,你需要先完成课程1,我们用一个匹配来表示他们:[0, 1]。给定课程总量以及它们的先决条件,判断是否可能完成所有课程的学习?
时间限制:1000
内存限制:65536
输入
多组数据。每组数据第一行是n和m,n表示有n门课程,m表示有m组依赖关系,接下来的m行是依赖关系的具体信息a b,表示第a门课程依赖第b门课程。 0<=n <=1000,0 <= m <= 4000 两组数据之间可能有空行
输出
对每组数据,能完成输出 True,不能完成输出 False
样例输入
2 1
1 0
2 2
1 0
0 1
样例输出
True
False
提示
示例2解释: 总共有2门课程。学习课程1之前,你需要先完成课程0;并且学习课程0之前,你还应先完成课程1。这是不可能的。

以下是使用C语言编写的解决方案:

#include 
#include 

#define MAX_COURSES 1000
#define MAX_DEPENDENCIES 4000

bool canFinish(int numCourses, int** prerequisites, int prerequisitesSize, int* prerequisitesColSize) {
    int indegree[MAX_COURSES] = {0};  // 存储每门课程的入度
    int adjacency[MAX_COURSES][MAX_COURSES] = {0};  // 存储课程之间的依赖关系

    // 统计每门课程的入度和依赖关系
    for (int i = 0; i < prerequisitesSize; i++) {
        indegree[prerequisites[i][0]]++;
        adjacency[prerequisites[i][1]][prerequisites[i][0]] = 1;
    }

    int queue[MAX_COURSES];  // 存储拓扑排序的队列
    int front = 0;  // 队列的头指针
    int rear = 0;  // 队列的尾指针

    // 将入度为0的课程入队
    for (int i = 0; i < numCourses; i++) {
        if (indegree[i] == 0) {
            queue[rear++] = i;
        }
    }

    int count = 0;  // 记录已学习的课程数量

    // 进行拓扑排序
    while (front < rear) {
        int course = queue[front++];  // 出队一个课程
        count++;  // 学习了一个课程

        // 更新与该课程有依赖关系的课程的入度
        for (int i = 0; i < numCourses; i++) {
            if (adjacency[course][i] == 1) {
                indegree[i]--;
                if (indegree[i] == 0) {
                    queue[rear++] = i;  // 入度为0的课程入队
                }
            }
        }
    }

    return count == numCourses;  // 如果学习的课程数量等于总课程数量,则能完成学习
}

int main() {
    int n, m;  // 课程总量和依赖关系数量

    while (scanf("%d%d", &n, &m) != EOF) {
        int prerequisites[MAX_DEPENDENCIES][2];  // 存储依赖关系

        // 读取依赖关系
        for (int i = 0; i < m; i++) {
            scanf("%d%d", &prerequisites[i][0], &prerequisites[i][1]);
        }

        // 调用函数判断是否能完成所有课程的学习
        bool result = canFinish(n, prerequisites, m, NULL);

        // 输出结果
        if (result) {
            printf("True\n");
        } else {
            printf("False\n");
        }
    }

    return 0;
}

你可以将以上代码保存为一个名为course_schedule.c的文件,然后使用C编译器进行编译和执行。

程序使用拓扑排序算法来判断是否能完成所有课程的学习。

首先,定义了一个canFinish函数,接收课程总量numCourses、依赖关系数组prerequisites、依赖关系数量prerequisitesSize和依赖关系列数prerequisitesColSize作为参数,并返回一个布尔值。

canFinish函数中,使用数组indegree来存储每门课程的入度,数组adjacency来存储课程之间的依赖关系。

然后,统计每门课程的入度和依赖关系。遍历依赖关系数组prerequisites,将依赖关系存储到indegreeadjacency数组中。

接下来,使用队列来进行拓扑排序。定义一个队列queue,使用指针frontrear分别指向队列的头部和尾部。

第4题:最小新整数

给定一个十进制正整数n(0 < n < 1000000000),每个数位上数字均不为0。n的位数为m。 现在从m位中删除k位(0
时间限制:1000
内存限制:65536
输入
第一行t, 表示有t组数据; 接下来t行,每一行表示一组测试数据,每组测试数据包含两个数字n, k。
输出
t行,每行一个数字,表示从n中删除k位后得到的最小整数。
样例输入
2
9128456 2
1444 3
样例输出
12456
1

以下是使用C语言编写的解决方案:

#include 
#include 
#include 

// 函数:删除字符串中的指定位置字符
void deleteCharAt(char *str, int index) {
    int len = strlen(str);
    if (index >= 0 && index < len) {
        for (int i = index; i < len - 1; i++) {
            str[i] = str[i + 1];
        }
        str[len - 1] = '\0';
    }
}

// 函数:删除k个字符后得到的最小整数
void getMinInteger(char *num, int k) {
    int len = strlen(num);
    if (k >= len) {
        printf("0\n");  // 删除的字符数大于等于字符串长度,直接输出0
        return;
    }

    while (k > 0) {
        int i = 0;
        while (i < strlen(num) - 1 && num[i] <= num[i + 1]) {
            i++;
        }
        deleteCharAt(num, i);
        k--;
    }

    printf("%s\n", num);
}

int main() {
    int t;  // 测试数据组数
    scanf("%d", &t);

    for (int i = 0; i < t; i++) {
        char num[20];  // 存储输入的数字
        int k;  // 删除的字符数
        scanf("%s%d", num, &k);
        getMinInteger(num, k);
    }

    return 0;
}

程序首先定义了一个deleteCharAt函数,用于删除字符串中的指定位置字符。接收一个字符串str和一个索引index作为参数,将索引位置的字符删除。

然后定义了一个getMinInteger函数,用于计算删除k个字符后得到的最小整数。接收一个字符串num和一个整数k作为参数。

getMinInteger函数中,首先判断删除的字符数k是否大于等于字符串的长度。如果是,则直接输出0。

接下来,使用一个循环,每次循环中找到第一个递减的字符,并删除该字符。循环执行k次。

最后,输出最小整数。

main函数中,首先读取测试数据组数t

然后,使用一个循环,依次读取每组测试数据的数字和删除的字符数,并调用getMinInteger函数进行计算和输出。

你可能感兴趣的:(c语言,c++,等级考试,电子学会,算法)