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

news2024/11/27 4:16:00

在这里插入图片描述

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

第1题:红与黑

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





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

下面是一个使用C语言编写的解决方案,根据题目描述,使用深度优先搜索算法来遍历所有相邻的黑色瓷砖。

#include <stdio.h>

#define MAX_W 20
#define MAX_H 20

int W, H; // 瓷砖的宽度和高度
char tiles[MAX_H][MAX_W]; // 瓷砖的颜色
int visited[MAX_H][MAX_W]; // 记录是否访问过

int dx[] = {1, -1, 0, 0}; // x 方向的偏移量
int dy[] = {0, 0, 1, -1}; // y 方向的偏移量

int count; // 计数器

void dfs(int x, int y) {
    visited[x][y] = 1; // 标记为已访问
    count++; // 计数器加一

    int i;
    for (i = 0; i < 4; i++) {
        int nx = x + dx[i];
        int ny = y + dy[i];

        // 判断相邻瓷砖是否在范围内且为黑色且未访问过
        if (nx >= 0 && nx < H && ny >= 0 && ny < W && tiles[nx][ny] == '.' && !visited[nx][ny]) {
            dfs(nx, ny); // 递归调用
        }
    }
}

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

        int i, j;
        int startX, startY; // 初始位置坐标

        // 读取瓷砖颜色并找到初始位置
        for (i = 0; i < H; i++) {
            for (j = 0; j < W; j++) {
                scanf(" %c", &tiles[i][j]);
                visited[i][j] = 0; // 初始化visited数组

                if (tiles[i][j] == '@') {
                    startX = i;
                    startY = j;
                }
            }
        }

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

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

    return 0;
}

这个程序使用深度优先搜索算法来遍历所有相邻的黑色瓷砖。首先,我们读取输入的瓷砖颜色,并找到初始位置。然后,我们使用递归的深度优先搜索函数dfs来遍历与当前位置相邻的黑色瓷砖。在搜索过程中,我们使用visited数组来记录已经访问过的瓷砖,避免重复访问和陷入死循环。最后,我们输出计数器count的值,即从初始位置出发能够到达的瓷砖数。

请注意,这个程序假设输入的数据是合法的,即初始位置@在每个数据集合中唯一出现一次,并且输入的瓷砖数量不超过20。在实际应用中,你可能需要添加一些错误处理的代码来处理异常情况。

第2题:迷宫问题

定义一个二维数组:
int maze[5][5] = {
0, 1, 0, 0, 0,
0, 1, 0, 1, 0,
0, 0, 0, 0, 0,
0, 1, 1, 1, 0,
0, 0, 0, 1, 0,
};
它表示一个迷宫, 其中的 1 表示墙壁, 0 表示可以走的路, 只能横着走或竖着走, 不能斜着走, 要求编程序找出从左上角到右下角的最短路线。
时间限制: 1000
内存限制: 65536
输入
一个 5 × 5 的二维数组, 表示一个迷宫。 数据保证有唯一解。
输出
左上角到右下角的最短路径, 格式如样例所示。
样例输入
0 1 0 0 0
0 1 0 1 0
0 0 0 0 0
0 1 1 1 0
0 0 0 1 0
样例输出
(0, 0)
(1, 0)
(2, 0)
(2, 1)
(2, 2)
(2, 3)
(2, 4)
(3, 4)
(4, 4)

下面是一个使用C语言编写的解决方案,使用广度优先搜索算法来找到从左上角到右下角的最短路径。

#include <stdio.h>
#include <stdbool.h>

#define ROWS 5
#define COLS 5

typedef struct {
    int row;
    int col;
} Point;

Point queue[ROWS * COLS]; // 队列,用于广度优先搜索
int front, rear; // 队列的前后指针

int maze[ROWS][COLS] = {
    {0, 1, 0, 0, 0},
    {0, 1, 0, 1, 0},
    {0, 0, 0, 0, 0},
    {0, 1, 1, 1, 0},
    {0, 0, 0, 1, 0}
};

bool visited[ROWS][COLS]; // 记录是否访问过
Point prev[ROWS][COLS]; // 记录路径上各点的前驱点

int dx[] = {0, 1, 0, -1}; // x 方向的偏移量
int dy[] = {-1, 0, 1, 0}; // y 方向的偏移量

void enqueue(Point p) {
    queue[rear++] = p;
}

Point dequeue() {
    return queue[front++];
}

bool isQueueEmpty() {
    return front == rear;
}

void printPath(Point p) {
    if (p.row == 0 && p.col == 0) {
        printf("(%d, %d)\n", p.row, p.col);
        return;
    }
    printPath(prev[p.row][p.col]);
    printf("(%d, %d)\n", p.row, p.col);
}

void bfs() {
    Point start = {0, 0};
    Point end = {ROWS - 1, COLS - 1};

    front = rear = 0; // 初始化队列
    enqueue(start);
    visited[start.row][start.col] = true;

    while (!isQueueEmpty()) {
        Point current = dequeue();

        if (current.row == end.row && current.col == end.col) {
            printPath(current);
            return;
        }

        int i;
        for (i = 0; i < 4; i++) {
            int newRow = current.row + dy[i];
            int newCol = current.col + dx[i];

            if (newRow >= 0 && newRow < ROWS && newCol >= 0 && newCol < COLS &&
                maze[newRow][newCol] == 0 && !visited[newRow][newCol]) {
                Point next = {newRow, newCol};
                enqueue(next);
                visited[newRow][newCol] = true;
                prev[newRow][newCol] = current;
            }
        }
    }
}

int main() {
    bfs();

    return 0;
}

这个程序使用广度优先搜索算法来找到从左上角到右下角的最短路径。首先,我们定义了一个点的结构体Point,用于表示迷宫中的坐标。然后,我们定义了一个队列queue,用于广度优先搜索。我们使用visited数组来记录已经访问过的点,避免重复访问。prev数组用于记录路径上各点的前驱点,以便最后打印出最短路径。

bfs函数中,我们使用队列来进行广度优先搜索。我们从起点开始,将其入队,并标记为已访问。然后,我们循环执行以下步骤,直到队列为空或者找到终点:

  • 出队一个点,记为current

  • 如果current是终点,说明已经找到最短路径,打印出路径并返回。

  • 否则,对current的四个相邻点进行判断:

    • 如果相邻点在迷宫范围内、为可通行的路且未访问过,将其入队,并标记为已访问。同时,记录该相邻点的前驱点为current

最后,在main函数中调用bfs函数进行搜索,并输出最短路径。

第3题:二叉树的深度

给定一棵二叉树, 求该二叉树的深度
二叉树深度定义: 从根结点到叶结点依次经过的结点(含根、叶结点)
形成树的一条路径, 最长路径的节点个数为树的深度
时间限制: 1000
内存限制: 65535
输入
第一行是一个整数 n, 表示二叉树的结点个数。 二叉树结点编号从 1到 n, 根结点为 1, n <= 10 接下来有 n 行, 依次对应二叉树的 n 个节点。 每行有两个整数, 分别表示该节点的左儿子和右儿子的节点编号。 如果第一个(第二个) 数为-1 则表示没有左(右) 儿子
输出
输出一个整型数, 表示树的深度
样例输入
3
2 3
-1 -1
-1 -1
样例输出
2

下面是一个使用C语言编写的解决方案,使用递归方法来求解二叉树的深度。

#include <stdio.h>

typedef struct TreeNode {
    int val;
    struct TreeNode* left;
    struct TreeNode* right;
} TreeNode;

int maxDepth(struct TreeNode* root) {
    if (root == NULL) {
        return 0;
    }

    int leftDepth = maxDepth(root->left);
    int rightDepth = maxDepth(root->right);

    return (leftDepth > rightDepth) ? leftDepth + 1 : rightDepth + 1;
}

int main() {
    int n;
    scanf("%d", &n);

    TreeNode* nodes[n];
    int i;
    for (i = 0; i < n; i++) {
        nodes[i] = (TreeNode*)malloc(sizeof(TreeNode));
        nodes[i]->val = i + 1;
        nodes[i]->left = NULL;
        nodes[i]->right = NULL;
    }

    for (i = 0; i < n; i++) {
        int left, right;
        scanf("%d %d", &left, &right);
        if (left != -1) {
            nodes[i]->left = nodes[left - 1];
        }
        if (right != -1) {
            nodes[i]->right = nodes[right - 1];
        }
    }

    int depth = maxDepth(nodes[0]);
    printf("%d\n", depth);

    return 0;
}

这个程序使用了递归方法来求解二叉树的深度。首先,我们定义了一个结构体TreeNode来表示二叉树的节点。每个节点包含一个值val,以及左右子节点的指针leftright。然后,我们定义了一个递归函数maxDepth,用于计算二叉树的深度。

maxDepth函数中,我们首先判断当前节点是否为空。如果为空,说明到达了叶节点,返回深度0。否则,我们递归调用maxDepth函数来计算左子树和右子树的深度,然后将左右子树中较大的深度加1作为当前节点的深度,并返回该值。

main函数中,我们首先读取输入的节点个数n。然后,我们根据节点个数创建节点数组nodes,并初始化每个节点的值和指针。接下来,我们按照输入的节点信息构建二叉树,将节点的左右子节点指向对应的节点。最后,我们调用maxDepth函数计算二叉树的深度,并将结果输出。

第4题:表达式· 表达式树· 表达式求值

众所周知, 任何一个表达式, 都可以用一棵表达式树来表示。 例如,
表达式 a+b*c, 可以表示为如下的表达式树:
+
/ \
a *
/ \
b c
现在, 给你一个中缀表达式, 这个中缀表达式用变量来表示(不含数字), 请你将这个中缀表达式用表达式二叉树的形式输出出来。
时间限制: 1000
内存限制: 65535
输入
输入分为三个部分。 第一部分为一行, 即中缀表达式(长度不大于 50)。
中缀表达式可能含有小写字母代表变量(a-z), 也可能含有运算符(+、-、 *、 /、 小括号), 不含有数字, 也不含有空格。 第二部分为一个整数 n(n < 10), 表示中缀表达式的变量数。 第三部分有 n 行, 每行格式为 C x, C 为变量的字符, x 为该变量的值。
输出
输出分为三个部分, 第一个部分为该表达式的逆波兰式, 即该表达式树的后根遍历结果。 占一行。 第二部分为表达式树的显示, 如样例输出所示。 如果该二叉树是一棵满二叉树, 则最底部的叶子结点, 分别占据横坐标的第 1、 3、 5、 7……个位置(最左边的坐标是 1), 然后它们的父结点的横坐标, 在两个子结点的中间。 如果不是满二叉树,则没有结点的地方, 用空格填充(但请略去所有的行末空格)。 每一行父结点与子结点中隔开一行, 用斜杠(/) 与反斜杠(\) 来表示树的关系。 /出现的横坐标位置为父结点的横坐标偏左一格, \出现的横坐标位置为父结点的横坐标偏右一格。 也就是说, 如果树高为 m, 则输出就有 2m-1 行。 第三部分为一个整数, 表示将值代入变量之后,该中缀表达式的值。 需要注意的一点是, 除法代表整除运算, 即舍弃小数点后的部分。 同时, 测试数据保证不会出现除以 0 的现象。
样例输入
a+b*c
3
a 2
b 7
c 5
样例输出
abc*+
+
/ \
a *
/ \
b c
37

以下是一个使用C语言编写的解决方案,实现了将中缀表达式转换为表达式树的功能:

#include <stdio.h>
#include <stdlib.h>

struct Node {
    char data;
    struct Node* left;
    struct Node* right;
};

// 创建一个新的表达式树结点
struct Node* createNode(char data) {
    struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
    newNode->data = data;
    newNode->left = NULL;
    newNode->right = NULL;
    return newNode;
}

// 判断一个字符是否是运算符
int isOperator(char c) {
    if (c == '+' || c == '-' || c == '*' || c == '/')
        return 1;
    return 0;
}

// 构建表达式树
struct Node* buildExpressionTree(char* infixExpression, int* index) {
    struct Node* root = NULL;
    if (isOperator(infixExpression[*index])) {
        root = createNode(infixExpression[*index]);
        (*index)++;
        root->left = buildExpressionTree(infixExpression, index);
        (*index)++;
        root->right = buildExpressionTree(infixExpression, index);
    } else {
        root = createNode(infixExpression[*index]);
    }
    return root;
}

// 后根遍历表达式树,得到逆波兰式
void postOrderTraversal(struct Node* root) {
    if (root == NULL)
        return;
    postOrderTraversal(root->left);
    postOrderTraversal(root->right);
    printf("%c", root->data);
}

// 打印表达式树
void printExpressionTree(struct Node* root, int space) {
    if (root == NULL)
        return;

    space += 4;

    printExpressionTree(root->right, space);

    printf("\n");
    for (int i = 4; i < space; i++)
        printf(" ");
    printf("%c\n", root->data);

    printExpressionTree(root->left, space);
}

// 获取变量对应的值
int getVariableValue(char variable, char* variables, int* values, int numVariables) {
    for (int i = 0; i < numVariables; i++) {
        if (variables[i] == variable)
            return values[i];
    }
    return 0;
}

// 计算表达式树的值
int evaluateExpressionTree(struct Node* root, char* variables, int* values, int numVariables) {
    if (root == NULL)
        return 0;

    if (!isOperator(root->data))
        return getVariableValue(root->data, variables, values, numVariables);

    int leftValue = evaluateExpressionTree(root->left, variables, values, numVariables);
    int rightValue = evaluateExpressionTree(root->right, variables, values, numVariables);

    switch (root->data) {
        case '+':
            return leftValue + rightValue;
        case '-':
            return leftValue - rightValue;
        case '*':
            return leftValue * rightValue;
        case '/':
            return leftValue / rightValue; // 整除运算
    }

    return 0;
}

int main() {
    char infixExpression[51];
    int numVariables;

    // 读取输入
    scanf("%s", infixExpression);
    scanf("%d", &numVariables);

    char variables[10];
    int values[10];

    // 读取变量及其值
    for (int i = 0; i < numVariables; i++) {
        scanf(" %c %d", &variables[i], &values[i]);
    }

    int index = 0;
    struct Node* root = buildExpressionTree(infixExpression, &index);

    // 输出逆波兰式
    postOrderTraversal(root);
    printf("\n");

    // 输出表达式树
    printExpressionTree(root, 0);

    // 计算表达式的值
    int result = evaluateExpressionTree(root, variables, values, numVariables);
    printf("%d\n", result);

    return 0;
}

请注意,上述代码假设输入的中缀表达式是合法的,并且变量的个数不超过10。同时,代码中使用了递归的方式构建表达式树,并通过后根遍历打印逆波兰式,使用中序遍历打印表达式树,并计算表达式的值。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/969175.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Aqs的CyclicBarrier。

今天我们来学习AQS家族的“外门弟子”&#xff1a;CyclicBarrier。 为什么说CyclicBarrier是AQS家族的“外门弟子”呢&#xff1f;那是因为CyclicBarrier自身和内部类Generation并没有继承AQS&#xff0c;但在源码的实现中却深度依赖AQS家族的成员ReentrantLock。就像修仙小说…

Java 复习笔记 - 学生管理系统篇

文章目录 学生管理系统一&#xff0c;需求部分需求分析初始菜单学生类添加功能删除功能修改功能查询功能 二&#xff0c;实现部分&#xff08;一&#xff09;初始化主界面&#xff08;二&#xff09;编写学生类&#xff08;三&#xff09;编写添加学生方法&#xff08;四&#…

ref 操作 React 定时器

秒表 需要将 interval ID 保存在 ref 中&#xff0c;以便在需要时能够清除计时器。 import { useRef, useState } from "react";const SecondWatch () > {const [startTime, setStartTime] useState<any>(null);const [now, setNow] useState<any>…

Elasticsearch中RestClient使用

&#x1f353; 简介&#xff1a;java系列技术分享(&#x1f449;持续更新中…&#x1f525;) &#x1f353; 初衷:一起学习、一起进步、坚持不懈 &#x1f353; 如果文章内容有误与您的想法不一致,欢迎大家在评论区指正&#x1f64f; &#x1f353; 希望这篇文章对你有所帮助,欢…

如何将自己的镜像使用 helm 部署

本文分别从如下几个方面来分享一波 如何将自己的镜像使用 helm 部署 简单介绍一下 helm 使用自己写 yaml 文件的方式在 k8s 中部署应用 使用 helm 的方式在 k8s 中部署应用 简单介绍一下 helm Helm 是 Kubernetes 的包管理器&#xff0c;在云原生领域用于应用打包和分发 Hel…

12. 微积分 - 梯度积分

Hi,大家好。我是茶桁。 上一节课,我们讲了方向导数,并且在最后留了个小尾巴,是什么呢?就是梯度。 我们再来回看一下但是的这个式子: [ f x f y

信息系统项目管理师(第四版)教材精读思维导图-第八章项目整合管理

请参阅我的另一篇文章&#xff0c;综合介绍软考高项&#xff1a; 信息系统项目管理师&#xff08;软考高项&#xff09;备考总结_计算机技术与软件专业技术_铭记北宸的博客-CSDN博客 本章思维导图PDF格式 本章思维导图XMind源文件 目录 8.1 管理基础 8.2 管理过程 8.3 制定项…

LRU算法 vs Redis近似LRU算法

LRU(Least Recently Use)算法&#xff0c;是用来判断一批数据中&#xff0c;最近最少使用算法。它底层数据结构由Hash和链表结合实现&#xff0c;使用Hash是为了保障查询效率为O(1)&#xff0c;使用链表保障删除元素效率为O(1)。 LRU算法是用来判断最近最少使用到元素&#xf…

最短路Dijkstra,spfa,图论二分图算法AYIT---ACM训练(模板版)

文章目录 前言A - Dijkstra Algorithm0x00 算法题目0x01 算法思路0x02 代码实现 B - 最长路0x00 算法题目0x01 算法思路0x02 代码实现 C - 二分图最大匹配0x00 算法题目0x01 算法思路0x02 代码实现 D - 搭配飞行员0x00 算法题目0x01 算法思路0x02 代码实现 E - The Perfect Sta…

企业架构LNMP学习笔记11

Nginx配置文件的介绍&#xff1a; #nginx子进程启动用户 #user nobody; #子进程数量 一般调整为cpu核数或者倍数 worker_processes 1; #错误日志定义 #error_log logs/error.log; #error_log logs/error.log notice; #error_log logs/error.log info;#进程pid 存储文件…

ISO/IEC/ITU标准如何快速查找(三十九)

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 人生格言: 人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药. 更多原创,欢迎关注:Android…

C++中的语法知识虚继承和虚基类

多继承(Multiple Inheritance)是指从多个直接基类中产生派生类的能力,多继承的派生类继承了所有父类的成员。尽管概念上非常简单,但是多个基类的相互交织可能会带来错综复杂的设计问题,命名冲突就是不可回避的一个。 多继承时很容易产生命名冲突,即使我们很小心地将所有类…

UDP和TCP协议报文格式详解

在初识网络原理(初识网络原理_蜡笔小心眼子&#xff01;的博客-CSDN博客)这篇博客中,我们简单的了解了一下TCP/IP五层网络模型,这篇博客将详细的学习一下五层网络模型中传输层的两个著名协议:UDP和TCP 目录 一, 传输层的作用 二, UDP 1,UDP协议的特点 2,UDP报文格式 三, TC…

【数据结构】如何设计循环队列?图文解析(LeetCode)

LeetCode链接&#xff1a;622. 设计循环队列 - 力扣&#xff08;LeetCode&#xff09; 目录 做题思路 只开辟 k 个空间 多开一个空间 代码实现 1. 循环队列的结构 2. 开辟空间 3. 判断空 4. 判断满 5. 队尾插入数据 6. 队头删除数据 7. 获取队头元素 8. 获取队尾元…

ElasticSearch第二讲:ES详解 - ElasticSearch基础概念

ElasticSearch第二讲&#xff1a;ES详解 - ElasticSearch基础概念 在学习ElasticSearch之前&#xff0c;先简单了解下ES流行度&#xff0c;使用背景&#xff0c;以及相关概念等。本文是ElasticSearch第二讲&#xff0c;ElasticSearch的基础概念。 文章目录 ElasticSearch第二讲…

【GoldenDict】win11牛津高阶英汉双解词典安装使用方法

【词典资源】 1&#xff08;本文章使用的版本&#xff09;牛津高阶&#xff08;第10版 英汉双解&#xff09; V11.8&#xff1a; https://pan.baidu.com/s/11272Cldde_2UttQkWS2MlQ 提取码&#xff1a;0p3j 2&#xff08;另一版本&#xff09;第十版 v13.2&#xff1a; ht…

信息系统项目管理师(第四版)教材精读思维导图-第九章项目范围管理

请参阅我的另一篇文章&#xff0c;综合介绍软考高项&#xff1a; 信息系统项目管理师&#xff08;软考高项&#xff09;备考总结_计算机技术与软件专业技术_铭记北宸的博客-CSDN博客 本章思维导图PDF格式 本章思维导图XMind源文件 目录 9.1 管理基础 9.2 管理过程 9.3 规划范…

【Linux】线程安全-信号量

文章目录 信号量原理信号量保证同步和互斥的原理探究信号量相关函数初始化信号量函数等待信号量函数释放信号量函数销毁信号量函数 信号量实现生产者消费者模型 信号量原理 信号量的原理&#xff1a;资源计数器 PCB等待队列 函数接口 资源计数器&#xff1a;对共享资源的计…

Python之单调栈

单调栈 了解单调栈先要了解栈。栈&#xff08;stack&#xff09;又名堆栈&#xff0c;它是一种运算受限的线性表。限定仅在表尾进行插入和删除操作的线性表。这一端被称为栈顶&#xff0c;相对地&#xff0c;把另一端称为栈底。向一个栈插入新元素又称作进栈、入栈或压栈&…

用JAVA(springboot) 开发的彩票模拟系统

闲暇时间&#xff0c;自己写了一个模拟彩票系统&#xff0c;里面研究了开奖算法&#xff0c;下单算法&#xff0c;彩票的各种计算规则。需要源码的私信&#xff0c;研究为主&#xff0c;切勿商务用途。