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

news2024/11/20 13:34:48

在这里插入图片描述

第1题:逃离迷宫

你在一个地下迷宫中找到了宝藏,但是也触发了迷宫机关,导致迷宫将在T分钟后坍塌,为此你需要在T分钟内逃离迷宫,你想知道你能不能逃离迷宫。迷宫是一个边长为m的正方形,其中"S"表示你所在的位置,“E"表示迷宫出口,”.“是可以随意走动的区域,”#“是不可穿行的墙壁,每次你可以耗费1分钟在区域间移动(上下左右四个方向)。
时间限制:1000
内存限制:65536
输入
输入包含多组数组,第一行是一个整数K(1 <= K <= 10),表示有K组数据。接下来每组数组包含整数m(2<=m<=10)和整数T,m表示正方形迷宫的边长,T表示坍塌时间。其后是一个m*m的字符矩阵,包含字符"S”, “E”, “.“和”#”。
输出
每组数据输出一行,输出“YES"或者"NO",表示是否可以在坍塌之前逃离(也就是说移动次数是否可以不超过T)。
样例输入
2
4 7
S…
###.
.#E.
…#.
3 4
S…
…#
.#E
样例输出
YES
NO

这个问题可以通过搜索剪枝技术来解决,具体算法如下:

  1. 定义一个二维数组visited,用于记录每个位置是否被访问过。

  2. 定义一个队列queue,用于存储待访问的位置。

  3. 定义一个变量time,用于记录已经消耗的时间。

  4. 找到起始位置"S"的坐标,并将其标记为已访问,并将其入队。

  5. 使用BFS(广度优先搜索)遍历迷宫,直到队列为空或时间超过T:

  • 从队列中取出一个位置。

  • 如果该位置是出口"E",则返回"YES"。

  • 遍历该位置的上下左右四个方向的相邻位置:

    • 如果该相邻位置是合法的且未被访问过:

      • 将该相邻位置标记为已访问。

      • 将该相邻位置入队。

  • 每次遍历完一层(即消耗了1分钟),将time加1。

  1. 如果时间超过了T,返回"NO";否则返回"YES"。

下面是使用C语言实现的代码:

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

#define MAX_SIZE 10

// 结构体表示坐标
typedef struct {
    int x;
    int y;
} Coordinate;

// 判断坐标是否在迷宫内
bool isValid(int x, int y, int N) {
    return (x >= 0 && x < N && y >= 0 && y < N);
}

// 判断坐标是否可以通过
bool isPassable(char maze[MAX_SIZE][MAX_SIZE], int x, int y) {
    return (maze[x][y] == '.' || maze[x][y] == 'E');
}

// 使用BFS搜索迷宫
bool canEscapeMaze(char maze[MAX_SIZE][MAX_SIZE], int N, int T) {
    int visited[MAX_SIZE][MAX_SIZE] = {0};
    int time = 0;
    Coordinate start;
    Coordinate end;

    // 找到起始位置和出口位置
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) {
            if (maze[i][j] == 'S') {
                start.x = i;
                start.y = j;
            } else if (maze[i][j] == 'E') {
                end.x = i;
                end.y = j;
            }
        }
    }

    // 定义四个方向的偏移量
    int dx[] = {-1, 1, 0, 0};
    int dy[] = {0, 0, -1, 1};

    visited[start.x][start.y] = 1;

    // 定义队列
    Coordinate queue[MAX_SIZE * MAX_SIZE];
    int front = 0;
    int rear = 0;
    queue[rear++] = start;

    // 使用BFS搜索迷宫
    while (front < rear && time <= T) {
        Coordinate current = queue[front++];
        
        // 到达出口,返回YES
        if (current.x == end.x && current.y == end.y) {
            return true;
        }
        
        // 遍历四个方向
        for (int i = 0; i < 4; i++) {
            int newX = current.x + dx[i];
            int newY = current.y + dy[i];

            if (isValid(newX, newY, N) && isPassable(maze, newX, newY) && !visited[newX][newY]) {
                visited[newX][newY] = visited[current.x][current.y] + 1;
                Coordinate newCoord;
                newCoord.x = newX;
                newCoord.y = newY;
                queue[rear++] = newCoord;
            }
        }
        
        // 消耗一分钟
        time++;
    }

    return false;
}

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

    while (K--) {
        int N, T;
        scanf("%d %d", &N, &T);

        char maze[MAX_SIZE][MAX_SIZE];

        // 读取迷宫
        for (int i = 0; i <```c
            N; i++) {
                scanf("%s", maze[i]);
            }

            // 判断是否可以逃离迷宫
            if (canEscapeMaze(maze, N, T)) {
                printf("YES\n");
            } else {
                printf("NO\n");
            }
        }

        return 0;
    }

这个程序使用了搜索剪枝技术来判断是否可以在规定时间内逃离迷宫。它通过BFS遍历迷宫,记录每个位置的访问状态和消耗时间,同时判断是否到达出口。如果在消耗的时间内到达出口,则返回"YES";否则返回"NO"。

第2题:夺宝探险

你无意中发现了装满了宝藏的迷宫,你想要获得尽可能多的宝藏,但是迷宫里的机关阻碍了你的计划。迷宫的地面是M行N列的矩形网格,每格是一块带有机关且放置了1个宝藏的地砖,宝藏一共有K种,用1-K表示其种类,迷宫的入口只有一个,为迷宫的第一行第一列。地砖的机关如下:
(1)每次你只能踏到你与你所在地砖相邻的地砖上(即前后左右4块);
(2)当你踏上某块地砖后,其上的宝藏(假设种类为k)自动归属你,同时所有放置了种类为k的宝藏的地砖碎裂,你无法踏上,你当前所在的地砖在你离开后也会立刻碎裂;
(3)当你无路可走的时候,你会被传送回迷宫出口,无法再进入迷宫。
你想知道你最多能获得多少宝藏。
时间限制:1000
内存限制:65536
输入
输入的第一行是三个用空格隔开的整数,分别是M、N和K(1 <= M,N <= 20, 1 <= K <= 100) 之后是M行,每行包含N个范围为1-K的整数,用空格隔开,表示放置的宝藏种类
输出
只有一行,为一个整数,表示最多能获得的宝藏个数。
样例输入
3 4 5
1 2 3 3
2 1 4 3
1 5 1 2
样例输出
4

根据题目描述,可以使用贪心算法来解决这个问题。贪心算法在每一步选择中都采取局部最优的策略,以期望最终达到全局最优。

具体算法如下:

  1. 定义一个二维数组maze,表示迷宫地砖的宝藏种类。

  2. 定义一个整数变量count,表示已获得的宝藏个数,初始化为0。

  3. 从迷宫的入口开始,用递归或循环的方式遍历迷宫的每个位置:

  • 如果当前位置的宝藏种类不为0(即还未被获得),则将该宝藏归属给你,宝藏个数加1,并将当前位置的宝藏种类置为0。

  • 在当前位置的上下左右四个方向中选择一个可行的方向,即该方向的位置在迷宫范围内且宝藏种类不为0。

  • 如果存在可行的方向,则沿着该方向继续前进。

  • 如果不存在可行的方向,则返回迷宫的入口位置,结束探险。

  1. 返回最终获得的宝藏个数count

下面是使用C语言实现的代码:

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

#define MAX_SIZE 20

int M, N, K;
int maze[MAX_SIZE][MAX_SIZE];

// 判断坐标是否在迷宫内
bool isValid(int x, int y) {
    return (x >= 0 && x < M && y >= 0 && y < N);
}

// 贪心算法探险
int exploreMaze(int x, int y) {
    if (!isValid(x, y) || maze[x][y] == 0) {
        return 0;
    }

    int currentTreasure = maze[x][y];
    maze[x][y] = 0;
    int count = 1;

    if (isValid(x + 1, y) && maze[x + 1][y] == currentTreasure) {
        count += exploreMaze(x + 1, y);
    }
    if (isValid(x - 1, y) && maze[x - 1][y] == currentTreasure) {
        count += exploreMaze(x - 1, y);
    }
    if (isValid(x, y + 1) && maze[x][y + 1] == currentTreasure) {
        count += exploreMaze(x, y + 1);
    }
    if (isValid(x, y - 1) && maze[x][y - 1] == currentTreasure) {
        count += exploreMaze(x, y - 1);
    }

    return count;
}

int main() {
    scanf("%d %d %d", &M, &N, &K);

    for (int i = 0; i < M; i++) {
        for (int j = 0; j < N; j++) {
            scanf("%d", &maze[i][j]);
        }
    }

    int maxTreasures = exploreMaze(0, 0);
    printf("%d\n", maxTreasures);

    return 0;
}

这个程序使用贪心算法来探险迷宫,并计算最多能获得的宝藏个数。它通过递归的方式遍历迷宫的每个位置,如果当前位置有宝藏并且存在可行的方向,就继续前进并累计宝藏个数。最终返回获得的宝藏个数count

注意:这个程序的实现假设迷宫的入口位置为(0, 0),即第一行第一列。如果迷宫的入口位置不是固定的,可以根据实际情况进行调整。

第3题:晶矿的个数

在某个区域发现了一些晶矿,已经探明这些晶矿总共有分为两类,为红晶矿和黑晶矿。现在要统计该区域内红晶矿和黑晶矿的个数。假设可以用二维地图m[][]来描述该区域,若m[i][j]为#表示该地点是非晶矿地点,若m[i][j]为r表示该地点是红晶矿地点,若m[i][j]为b表示该地点是黑晶矿地点。一个晶矿是由相同类型的并且上下左右相通的晶矿点组成。现在给你该区域的地图,求红晶矿和黑晶矿的个数。
时间限制:1000
内存限制:65536
输入
第一行为k,表示有k组测试输入。 每组第一行为n,表示该区域由n*n个地点组成,3 <= n<= 30 接下来n行,每行n个字符,表示该地点的类型。
输出
对每组测试数据输出一行,每行两个数字分别是红晶矿和黑晶矿的个数,一个空格隔开。
样例输入
2
6
r##bb#
###b##
#r##b#
#r##b#
#r####
######
4
####
#rrb
#rr#
##bb
样例输出
2 2
1 2

根据题目描述,我们可以使用搜索剪枝技术来解决这个问题。下面是使用C语言编写的解决方案:

#include <stdio.h>

#define MAX_SIZE 30

int countRed;
int countBlack;

void dfs(char map[][MAX_SIZE], int n, int row, int col, char type) {
    if (row < 0 || row >= n || col < 0 || col >= n || map[row][col] != type) {
        return;
    }

    map[row][col] = '#'; // 标记为非晶矿点,避免重复计数

    // 统计当前晶矿点
    if (type == 'r') {
        countRed++;
    } else if (type == 'b') {
        countBlack++;
    }

    // 递归搜索上下左右相邻的晶矿点
    dfs(map, n, row - 1, col, type);
    dfs(map, n, row + 1, col, type);
    dfs(map, n, row, col - 1, type);
    dfs(map, n, row, col + 1, type);
}

void countCrystals(char map[][MAX_SIZE], int n) {
    countRed = 0;
    countBlack = 0;

    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            if (map[i][j] == 'r' || map[i][j] == 'b') {
                dfs(map, n, i, j, map[i][j]);
            }
        }
    }

    printf("%d %d\n", countRed, countBlack);
}

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

    while (k--) {
        int n;
        scanf("%d", &n);

        char map[MAX_SIZE][MAX_SIZE];

        for (int i = 0; i < n; i++) {
            scanf("%s", map[i]);
        }

        countCrystals(map, n);
    }

    return 0;
}

这个解决方案使用了深度优先搜索(DFS)算法,通过递归地搜索相邻的晶矿点,并将其标记为非晶矿点,避免重复计数。在每次搜索过程中,统计红晶矿和黑晶矿的个数。最后输出结果。该算法的时间复杂度为O(n^2),其中n为地图的大小。

第4题:冠军之路

当训练师眼神对上的那一刻,就会开始对战。
lxz来到了冠军之路的山洞中。山洞的地图是一个N*M的矩形。在地图中,'.‘代表可以行走的地面,’#'代表无法行走的岩石。'I’代表山洞的入口,即lxz现在所在的位置。‘O’表示冠军之路的出口。lxz可以向上下左右四个方向行走。矩形的四周都是山洞的岩石,无法行走。
冠军之路中有一些精英训练师,他们可能面向上、下、左、右四个方向,在地图上用’w’,‘a’,‘s’,'d’表示,其中’w’表示向上。's’表示向下。'a’表示向左。'd’表示向右(这些位置不可行走)。如果lxz出现在精英训练师正对方向的一条线上,且没有被岩石或其他精英训练师阻挡,那么lxz就会与这个精英训练师进行对战。每位训练师只会与lxz对战一次。
为了通过冠军之路,lxz必须击败所有精英训练师。lxz希望找到一条击败所有精英训练师并走到冠军之路出口的最短路径。
时间限制:1000
内存限制:65536
输入
第一行是两个整数,N, M表示地图的大小。 0 < N, M <= 100 接下来是N行,每行M个字符,代表冠军之路的地图。训练师的个数不超过8
输出
一个整数,表示击败所有精英训练师并走到冠军之路出口的最短路径的长度。如果无法击败所有精英训练师或者无法到达出口,输出-1。
样例输入
3 3
Id.

Oa#
样例输出
8

根据题目描述,我们可以使用搜索剪枝技术来解决这个问题。下面是使用C语言编写的解决方案:

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

#define MAX_SIZE 100
#define INF 1000000

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

int N, M; // 地图的大小
char map[MAX_SIZE][MAX_SIZE]; // 地图
bool visited[MAX_SIZE][MAX_SIZE]; // 记录是否访问过
Position start; // 入口位置
Position end; // 出口位置
Position trainers[8]; // 训练师位置
int trainerCount; // 训练师个数
int minPath; // 最短路径的长度

int min(int a, int b) {
    return a < b ? a : b;
}

bool isValid(int row, int col) {
    return row >= 0 && row < N && col >= 0 && col < M && map[row][col] != '#';
}

void dfs(int row, int col, int path) {
    if (row == end.row && col == end.col) {
        if (path < minPath) {
            minPath = path;
        }
        return;
    }

    if (path >= minPath) {
        return;
    }

    visited[row][col] = true;

    if (map[row][col] != 'I' && map[row][col] != 'O') {
        for (int i = 0; i < trainerCount; i++) {
            if ((row == trainers[i].row || col == trainers[i].col) && !visited[trainers[i].row][trainers[i].col]) {
                return; // 与训练师在同一条线上,但被其他岩石或训练师阻挡
            }
        }
    }

    if (isValid(row - 1, col) && !visited[row - 1][col]) {
        dfs(row - 1, col, path + 1);
    }
    if (isValid(row + 1, col) && !visited[row + 1][col]) {
        dfs(row + 1, col, path + 1);
    }
    if (isValid(row, col - 1) && !visited[row][col - 1]) {
        dfs(row, col - 1, path + 1);
    }
    if (isValid(row, col + 1) && !visited[row][col + 1]) {
        dfs(row, col + 1, path + 1);
    }

    visited[row][col] = false;
}

int calculateMinPath() {
    memset(visited, false, sizeof(visited));
    minPath = INF;

    dfs(start.row, start.col, 0);

    return minPath != INF ? minPath : -1;
}

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

    for (int i = 0; i < N; i++) {
        scanf("%s", map[i]);

        for (int j = 0; j < M; j++) {
            if (map[i][j] == 'I') {
                start.row = i;
                start.col = j;
            } else if (map[i][j] == 'O') {
                end.row = i;
                end.col = j;
            } else if (map[i][j] >= 'a' && map[i][j] <= 'z') {
                trainers[trainerCount].row = i;
                trainers[trainerCount].col = j;
                trainerCount++;
            }
        }
    }

    int result = calculateMinPath();
    printf("%d\n", result);

    return 0;
}

这个解决方案使用了深度优先搜索(DFS)算法,在搜索的过程中,使用剪枝技术来提前终止不必要的搜索。首先,我们通过DFS找到从入口到出口的所有路径。在搜索过程中,我们记录训练师的位置,当lxz出现在精英训练师正对方向的一条线上,且没有被岩石或其他精英训练师阻挡时,我们返回到上一层递归,避免进一步搜索。最后,我们计算所有路径中的最短路径,并输出结果。

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

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

相关文章

完善会计流程的关键功能:了解必备的会计软件功能!

会计软件已经成为许多大小企业的财务管理标配。会计软件可以帮助企业自动化财务流程&#xff0c;提高工作效率&#xff0c;减少错误&#xff0c;并提供准确和可靠的财务数据。一款合格的会计软件应该具备什么功能呢&#xff1f; 会计软件应有的功能 1、账户管理&#xff1a;会…

overlayfs

参考&#xff1a;How containers work: overlayfs how overlays work Overlay filesystems, also known as “union filesystems” or “union mounts” let you mount a filesystem using 2 directories: a “lower” directory, and an “upper” directory. Basically: t…

C语言之练习题

欢迎来到我的&#xff1a;世界 希望作者的文章对你有所帮助&#xff0c;有不足的地方还请指正&#xff0c;大家一起学习交流 ! 目录 前言填空题&#xff1a;第一题第二题第三题第四题 编程题&#xff1a;第一题&#xff1a;第二题&#xff1a; 总结 前言 填空题&#xff1a; …

网御ACM上网行为管理系统bottomframe.cgi接口存在SQL注入漏洞 附POC

文章目录 网御ACM上网行为管理系统bottomframe.cgi接口存在SQL注入漏洞 附POC1. 网御ACM上网行为管理系统简介2.漏洞描述3.影响版本4.fofa查询语句5.漏洞复现6.POC&EXP7.整改意见8.往期回顾 网御ACM上网行为管理系统bottomframe.cgi接口存在SQL注入漏洞 附POC 免责声明&am…

three.js(九):内置的路径合成几何体

路径合成几何体 TubeGeometry 管道LatheGeometry 车削ExtrudeGeometry 挤压 TubeGeometry 管道 TubeGeometry(path : Curve, tubularSegments : Integer, radius : Float, radialSegments : Integer, closed : Boolean) path — Curve - 一个由基类Curve继承而来的3D路径。 De…

关于Linux系统时间的问题

关于Linux系统时间的问题 当我们进行一些特定的业务需求时&#xff0c;需要修改当前Linux系统的系统时间。我们可以用以下命令进行修改时间。 data -s "2022-08-31 15:00:00"当我们将时间设置为某个时间点后&#xff0c;Linux系统的时间会出现一个问题&#xff1a;…

React原理 - React Reconciliation-上

目录 扩展学习资料 React Reconciliation Stack Reconciler【15版本、栈协调】 Stack Reconciler-事务性 事务性带来的弊端&#xff1a; 扩展学习资料 名称 链接 备注 官方文档 Reconciliation – React 英文 stack reconciler Implementation Notes – React 英文…

IntelliJ IDEA 2023.2.1使用Git时弹出“使用访问令牌登录”问题解决

这里写目录标题 一、内网Git环境GitLabGogsGitea 二、外网Git环境GitHubGitee 升级为IntelliJ IDEA 2023.2.1后&#xff0c;使用Git时弹出“使用访问令牌登录”的窗口&#xff0c;习惯使用Git帐号密码登录的用户&#xff0c;面对这个突如其来的弹窗真的很懵。 一、内网Git环境 …

虚拟化技术原理

计算虚拟化 介绍 把物理主机上物理资源&#xff08;CPU&#xff0c;内存&#xff0c;IO外设&#xff09;&#xff0c;通过虚拟化层抽象成超量、等量的逻辑资源&#xff08;虚拟CPU&#xff0c;虚拟内存&#xff0c;虚拟IO设备&#xff09;&#xff0c;然后重新组合形成新的虚…

大数据学习:impala基础

impala基础 1. impala介绍 1.1 impala概述 Impala是Cloudera公司推出&#xff0c;提供对HDFS、Hbase数据的高性能、低延迟的交互式SQL查询功能。官方测试性能比hive快10到100倍&#xff0c;其sql查询比sparkSQL还要更加快速&#xff0c;号称是当前大数据领域最快的查询sq工具…

【排序】快排非递归

模拟递归的下标&#xff0c;让他们入栈

投票同款特效样式

先看效果&#xff1a; 再看代码&#xff08;查看更多&#xff09;&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Title</title><style>import url("https://fonts.…

vant2 van-calendar组件增加清除按钮和确定按钮

利用自定义插槽增加一个清除按钮 <van-calendar ref"fTime1" select"selectTimePicker" confirm"changeTimePicker" :default-date"null" :show-confirm"false" v-model"timePickerShow" type"range&quo…

《用行动打造满意的服务》考试答案

中电金信新员工入职培训选修课程《用行动打造满意的服务》考试答案

数据结构day08(树、算法)

今日任务&#xff1a; 二叉树&#xff1a; 今日思维导图 链接&#xff1a; 快排&#xff1a;快速排序法&#xff08;详解&#xff09;_李小白~的博客-CSDN博客图画挺好啊 常见款&#xff1a;https://www.runoob.com/w3cnote/quick-sort.html

18.2 【Linux】rsylog.service:记录登录文件的服务

rsyslogd 可以负责主机产生的各个信息的登录&#xff0c;而这些信息本身是有“严重等级”之分的。每个 Linux distributions 放置的登录文件文件名可能会有所差异。 基本上&#xff0c; rsyslogd 针对各种服务与讯息记录在某些文件的配置文件就是 /etc/rsyslog.conf&#xff0…

掌握逻辑漏洞复现技术,保护您的数字环境

环境准备 这篇文章旨在用于网络安全学习&#xff0c;请勿进行任何非法行为&#xff0c;否则后果自负。 1、支付逻辑漏洞 攻击相关介绍 介绍&#xff1a; 支付逻辑漏洞是指攻击者利用支付系统的漏洞&#xff0c;突破系统的限制&#xff0c;完成非法的支付操作。攻击者可以采…

c# - - - 安装.net core sdk

如图&#xff0c;安装的是.Net Core 2.2版本 查看安装成功