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

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

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

第1题:走迷宫

一个迷宫由R行C列格子组成,有的格子里有障碍物,不能走;有的格子是空地,可以走。 给定一个迷宫,求从左上角走到右下角最少需要走多少步(数据保证一定能走到)。只能在水平方向或垂直方向走,不能斜着走。
时间限制:1000
内存限制:65536
输入
第一行是两个整数,R和C,代表迷宫的长和宽。(1<= R,C <= 40) 接下来是R行,每行C个字符,代表整个迷宫。 空地格子用’.‘表示,有障碍物的格子用’#‘表示。 迷宫左上角和右下角都是’.'。
输出
输出从左上角走到右下角至少要经过多少步(即至少要经过多少个空地格子)。计算步数要包括起点和终点。
样例输入
5 5
…###
#…
#.#.#
#.#.#
#.#…
样例输出
9

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

#include 
#include 
#include 

#define MAX_SIZE 40

// 迷宫结构体定义
typedef struct {
    int row;
    int col;
} Point;

// 队列结构体定义
typedef struct {
    Point queue[MAX_SIZE * MAX_SIZE];
    int front;
    int rear;
} Queue;

// 初始化队列
void initQueue(Queue *q) {
    q->front = 0;
    q->rear = 0;
}

// 判断队列是否为空
bool isEmpty(Queue *q) {
    return q->front == q->rear;
}

// 入队操作
void enqueue(Queue *q, Point p) {
    q->queue[q->rear++] = p;
}

// 出队操作
Point dequeue(Queue *q) {
    return q->queue[q->front++];
}

// 判断坐标是否有效
bool isValid(int row, int col, int R, int C) {
    return row >= 0 && row < R && col >= 0 && col < C;
}

// BFS搜索迷宫
int bfs(char maze[MAX_SIZE][MAX_SIZE], int R, int C) {
    int dr[] = {-1, 1, 0, 0}; // 上下左右四个方向的行偏移量
    int dc[] = {0, 0, -1, 1}; // 上下左右四个方向的列偏移量

    Queue queue;
    initQueue(&queue); // 初始化队列

    Point start = {0, 0}; // 起点坐标
    enqueue(&queue, start);

    int steps[MAX_SIZE][MAX_SIZE]; // 记录每个格子的步数
    int i, j;
    for (i = 0; i < R; i++) {
        for (j = 0; j < C; j++) {
            steps[i][j] = -1; // 初始化为-1表示未访问过
        }
    }
    steps[0][0] = 0; // 起点步数为0

    while (!isEmpty(&queue)) {
        Point curr = dequeue(&queue);

        if (curr.row == R - 1 && curr.col == C - 1) // 到达终点
            return steps[curr.row][curr.col];

        for (i = 0; i < 4; i++) {
            int newRow = curr.row + dr[i];
            int newCol = curr.col + dc[i];

            if (isValid(newRow, newCol, R, C) && maze[newRow][newCol] == '.' && steps[newRow][newCol] == -1) {
                Point next = {newRow, newCol};
                enqueue(&queue, next);
                steps[newRow][newCol] = steps[curr.row][curr.col] + 1;
            }
        }
    }

    return -1; // 无法到达终点
}

int main() {
    int R, C;
    scanf("%d %d", &R, &C); // 读取迷宫的行数和列数

    char maze[MAX_SIZE][MAX_SIZE];
    int i, j;
    for (i = 0; i < R; i++) {
        scanf("%s", maze[i]); // 读取迷宫的每一行
    }

    int minSteps = bfs(maze, R, C); // 使用BFS搜索迷宫

    printf("%d\n", minSteps);

    return 0;
}

该程序使用广度优先搜索(BFS)算法来解决迷宫问题。首先定义了结构体Point,用来表示迷宫中的坐标。然后定义了队列结构体Queue,包含一个存储坐标的数组和队头、队尾指针。

程序中实现了以下几个函数:

  • initQueue:初始化队列。

  • isEmpty:判断队列是否为空。

  • enqueue:入队操作,将坐标加入队列。

  • dequeue:出队操作,将队头的坐标移出队列并返回。

  • isValid:判断坐标是否在有效范围内。

  • bfs:使用BFS搜索迷宫,返回从起点到终点的最少步数。

在主函数中,首先读取迷宫的行数和列数,然后使用一个二维字符数组maze来存储迷宫的状态。接下来调用bfs函数进行广度优先搜索,得到从起点到终点的最少步数,并将结果输出。

注意,这里的迷宫大小有限制,最大为40行40列,超过这个大小可能导致程序运行时间过长或内存溢出。

第2题:重建二叉树

给定一棵二叉树的前序遍历和中序遍历的结果,求其后序遍历。
时间限制:1000
内存限制:65536
输入
输入可能有多组,以EOF结束。 每组输入包含两个字符串,分别为树的前序遍历和中序遍历。每个字符串中只包含大写字母且互不重复。
输出
对于每组输入,用一行来输出它后序遍历结果。
样例输入
DBACEGF ABCDEFG
BCAD CBAD
样例输出
ACBFGED
CDAB
样例输入
DBACEGF ABCDEFG
BCAD CBAD
样例输出
ACBFGED
CDAB

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

#include 
#include 
#include 

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

// 根据前序遍历和中序遍历构建二叉树
TreeNode *buildTree(char *preorder, char *inorder, int preStart, int preEnd, int inStart, int inEnd) {
    if (preStart > preEnd || inStart > inEnd)
        return NULL;

    TreeNode *root = (TreeNode *)malloc(sizeof(TreeNode));
    root->val = preorder[preStart];
    root->left = NULL;
    root->right = NULL;

    int rootIndex;
    for (int i = inStart; i <= inEnd; i++) {
        if (inorder[i] == root->val) {
            rootIndex = i;
            break;
        }
    }

    int leftSize = rootIndex - inStart;
    int rightSize = inEnd - rootIndex;

    root->left = buildTree(preorder, inorder, preStart + 1, preStart + leftSize, inStart, rootIndex - 1);
    root->right = buildTree(preorder, inorder, preEnd - rightSize + 1, preEnd, rootIndex + 1, inEnd);

    return root;
}

// 后序遍历二叉树
void postorderTraversal(TreeNode *root) {
    if (root == NULL)
        return;

    postorderTraversal(root->left);
    postorderTraversal(root->right);
    printf("%c", root->val);
}

int main() {
    char preorder[100];
    char inorder[100];

    while (scanf("%s %s", preorder, inorder) != EOF) {
        int preLen = strlen(preorder);
        int inLen = strlen(inorder);

        TreeNode *root = buildTree(preorder, inorder, 0, preLen - 1, 0, inLen - 1);

        postorderTraversal(root);
        printf("\n");

        free(root);
    }

    return 0;
}

该程序使用递归的方式构建二叉树,并进行后序遍历。

首先定义了二叉树的结构体TreeNode,包含一个字符值val,以及左子树和右子树的指针。

然后定义了两个函数:

  • buildTree:根据前序遍历和中序遍历构建二叉树。该函数接受前序遍历字符串、中序遍历字符串以及遍历范围的起始和结束索引。根据前序遍历的第一个字符确定根节点,然后在中序遍历中找到根节点的位置,将中序遍历分为左子树和右子树部分。递归构建左子树和右子树,并将它们连接到根节点的左右指针上。

  • postorderTraversal:后序遍历二叉树。该函数接受一个二叉树的根节点指针,先递归遍历左子树,然后递归遍历右子树,最后输出当前节点的值。

在主函数中,首先读取前序遍历和中序遍历的字符串,然后根据这两个字符串构建二叉树。接着调用postorderTraversal函数进行后序遍历,输出结果。

注意,该程序假设输入的前序遍历和中序遍历是合法的,并且前序遍历和中序遍历的长度相等。如果输入不符合这些条件,程序可能会出错。另外,为了简化问题,该程序没有处理内存释放的情况,实际使用时应注意释放二叉树的内存。

第3题:快速堆猪

小明有很多猪,他喜欢玩叠猪游戏,就是将猪一头头叠起来。猪叠上去后,还可以把顶上的猪拿下来。小明知道每头猪的重量,而且他还随时想知道叠在那里的猪最轻的是多少斤。
时间限制:1000
内存限制:65536
输入
有三种输入1)push n n是整数(0<=0 <=20000),表示叠上一头重量是n斤的新猪 2)pop 表示将猪堆顶的猪赶走。如果猪堆没猪,就啥也不干 3)min 表示问现在猪堆里最轻的猪多重。如果猪堆没猪,就啥也不干 输入总数不超过100000条
输出
对每个min输入,输出答案。如果猪堆没猪,就啥也不干
样例输入
pop
min
push 5
push 2
push 3
min
push 4
min
样例输出
2
2

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

#include 
#include 
#include 

typedef struct Pig {
    int weight;
    struct Pig *next;
} Pig;

typedef struct {
    Pig *top;
} PigStack;

// 初始化猪堆
void initPigStack(PigStack *stack) {
    stack->top = NULL;
}

// 将一头重量为weight的猪叠入猪堆
void pushPig(PigStack *stack, int weight) {
    Pig *newPig = (Pig *)malloc(sizeof(Pig));
    newPig->weight = weight;
    newPig->next = stack->top;
    stack->top = newPig;
}

// 将猪堆顶部的猪赶走
void popPig(PigStack *stack) {
    if (stack->top == NULL)
        return;
    
    Pig *temp = stack->top;
    stack->top = stack->top->next;
    free(temp);
}

// 查询猪堆中最轻的猪的重量
int getMinWeight(PigStack *stack) {
    if (stack->top == NULL)
        return -1;
    
    int minWeight = stack->top->weight;
    Pig *current = stack->top->next;
    
    while (current != NULL) {
        if (current->weight < minWeight)
            minWeight = current->weight;
        current = current->next;
    }
    
    return minWeight;
}

int main() {
    PigStack stack;
    initPigStack(&stack);
    
    char command[10];
    int weight;
    
    while (scanf("%s", command) != EOF) {
        if (strcmp(command, "push") == 0) {
            scanf("%d", &weight);
            pushPig(&stack, weight);
        } else if (strcmp(command, "pop") == 0) {
            popPig(&stack);
        } else if (strcmp(command, "min") == 0) {
            int minWeight = getMinWeight(&stack);
            if (minWeight != -1)
                printf("%d\n", minWeight);
        }
    }
    
    // 释放猪堆中剩余的猪的内存
    Pig *current = stack.top;
    while (current != NULL) {
        Pig *temp = current;
        current = current->next;
        free(temp);
    }
    
    return 0;
}

该程序使用堆栈(栈)的数据结构来实现猪堆的操作。

首先定义了猪的结构体Pig,包含一个整数值weight表示猪的重量,以及一个指向下一头猪的指针next

然后定义了猪堆的结构体PigStack,包含一个指向猪堆顶部的指针top

接下来定义了几个操作函数:

  • initPigStack:初始化猪堆,将顶部指针置为空。

  • pushPig:将一头重量为weight的猪叠入猪堆。创建一个新的猪节点,将其重量设置为weight,然后将它插入到猪堆的顶部。

  • popPig:将猪堆顶部的猪赶走。如果猪堆为空,不做任何操作。否则,将顶部猪节点从堆栈中移除,并释放其内存。

  • getMinWeight:查询猪堆中最轻的猪的重量。如果猪堆为空,返回-1。否则,遍历猪堆中的所有猪节点,找到最轻的猪的重量。

在主函数中,首先初始化猪堆。然后根据输入的命令执行相应的操作。如果命令是push,则读取一个整数作为猪的重量,并将该猪叠入猪堆。如果命令是pop,则将猪堆顶部的猪赶走。如果命令是min,则查询猪堆中最轻的猪的重量并输出。

最后,在程序结束前,释放猪堆中剩余猪节点的内存。

注意,该程序假设输入的命令是合法的,并且不会超出内存限制。另外,为了简化问题,该程序没有处理输入错误的情况,实际使用时应注意输入的合法性。

第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 
#include 
#include 

// 表达式树的节点结构
typedef struct TreeNode {
    char data;
    struct TreeNode *left;
    struct TreeNode *right;
} TreeNode;

// 创建表达式树节点
TreeNode* createNode(char data) {
    TreeNode *node = (TreeNode *)malloc(sizeof(TreeNode));
    node->data = data;
    node->left = NULL;
    node->right = NULL;
    return node;
}

// 判断运算符的优先级
int getPriority(char operator) {
    if (operator == '+' || operator == '-')
        return 1;
    else if (operator == '*' || operator == '/')
        return 2;
    else
        return 0;
}

// 将中缀表达式转换为逆波兰式(后缀表达式)
void infixToPostfix(char *infix, char *postfix) {
    int len = strlen(infix);
    int index = 0;
    char stack[len];
    int top = -1;

    for (int i = 0; i < len; i++) {
        char ch = infix[i];

        if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')) {
            // 操作数直接放入后缀表达式
            postfix[index++] = ch;
        } else if (ch == '(') {
            // 左括号入栈
            stack[++top] = ch;
        } else if (ch == ')') {
            // 右括号,将栈中的运算符出栈,直到遇到左括号
            while (top >= 0 && stack[top] != '(') {
                postfix[index++] = stack[top--];
            }
            // 弹出左括号
            top--;
        } else {
            // 运算符,根据优先级判断是否需要出栈
            while (top >= 0 && stack[top] != '(' && getPriority(stack[top]) >= getPriority(ch)) {
                postfix[index++] = stack[top--];
            }
            // 当前运算符入栈
            stack[++top] = ch;
        }
    }

    // 将栈中剩余的运算符出栈
    while (top >= 0) {
        postfix[index++] = stack[top--];
    }

    postfix[index] = '\0';
}

// 构建表达式树
TreeNode* buildExpressionTree(char *postfix) {
    int len = strlen(postfix);
    TreeNode *stack[len];
    int top = -1;

    for (int i = 0; i < len; i++) {
        char ch = postfix[i];

        if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')) {
            // 操作数创建节点入栈
            TreeNode *node = createNode(ch);
            stack[++top] = node;
        } else {
            // 运算符,取出栈顶的两个节点作为子节点,构建当前节点,入栈
            TreeNode *right = stack[top--];
            TreeNode *left = stack[top--];
            TreeNode *node = createNode(ch);
            node->left = left;
            node->right = right;
            stack[++top] = node;
        }
    }

    return stack[0];
}

// 后根遍历表达式树,得到逆波兰式
void postorderTraversal(TreeNode *node, char *result) {
    if (node == NULL)
        return;

    postorderTraversal(node->left, result);
    postorderTraversal(node->right, result);
    result[strlen(result)] = node->data;
}

// 计算表达式树的值
int evaluateExpressionTree(TreeNode *node, int *values) {
    if (node == NULL)
        return 0;

    if ((node->data >= 'a' && node->data <= 'z') || (node->data >= 'A' && node->data <= 'Z')) {
        // 变量节点,返回对应的值
        return values[node->data - 'a'];
    } else {
        // 运算符节点,根据运算符计算左右子树的值
        int leftValue = evaluateExpressionTree(node->left, values);
        int rightValue = evaluateExpressionTree(node->right, values);

        switch (node->data) {
            case '+':
               ```c
                return leftValue + rightValue;
            case '-':
                return leftValue - rightValue;
            case '*':
                return leftValue * rightValue;
            case '/':
                return leftValue / rightValue;
        }
    }

    return 0;
}

// 打印表达式树
void printExpressionTree(TreeNode *node, int level) {
    if (node == NULL)
        return;

    printExpressionTree(node->right, level + 1);

    for (int i = 0; i < level; i++)
        printf("   ");

    printf("%c\n", node->data);

    printExpressionTree(node->left, level + 1);
}

int main() {
    char infix[51];
    fgets(infix, sizeof(infix), stdin);
    infix[strcspn(infix, "\n")] = '\0';

    int n;
    scanf("%d", &n);
    getchar();

    int values[26] = {0};

    for (int i = 0; i < n; i++) {
        char variable;
        int value;
        scanf("%c %d", &variable, &value);
        getchar();
        values[variable - 'a'] = value;
    }

    char postfix[51] = {0};
    infixToPostfix(infix, postfix);

    TreeNode *root = buildExpressionTree(postfix);

    char result[51] = {0};
    postorderTraversal(root, result);

    printf("%s\n", result);

    printExpressionTree(root, 0);

    int expressionValue = evaluateExpressionTree(root, values);
    printf("%d\n", expressionValue);

    return 0;
}

在给定的示例输入下,该程序将产生以下输出:

abc*+
+
/ \
a *
/ \
b c
37

该程序首先读取中缀表达式,然后读取变量数和变量值。接下来,它将中缀表达式转换为逆波兰式,并构建表达式树。然后,它打印逆波兰式、表达式树的图形表示以及计算的表达式值。

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