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

在这里插入图片描述

第1题:数字变换

给定一个包含5个数字(0-9)的字符串,例如 “02943”,请将“12345”变换到它。 你可以采取3种操作进行变换
(1)交换相邻的两个数字
(2)将一个数字加1。如果加1后大于9,则变为0
(3)将一个数字加倍。如果加倍后大于9,则将其变为加倍后的结果除以10的余数。
最多只能用第2种操作3次,第3种操作2次 求最少经过多少次操作可以完成变换。
时间限制:1000
内存限制:65536
输入
有最多 100,000 组数据 每组数据就是包含5个数字的字符串
输出
对每组数据,输出将12345变换到给定字符串所需要的最少操作步数。如果无法变换成功,输出-1
样例输入
12435
99999
12374
样例输出
1
-1
3
提示
由于测试数据太多,如果对每组数据都从头进行搜索,就会超时。 建议先做预处理,即以“12345”作为初始状态做一遍彻底的广搜,找出“12345”经合法变换能够到达的所有字符串,并记录到达这些字符串各需要多少步操作。 然后对读入的每组数据,在上述预处理记录的结果中进行查询即可。

这个问题可以使用广度优先搜索(BFS)来解决。首先,我们以"12345"作为初始状态,通过合法的操作进行广度优先搜索,找出所有可以到达的字符串,并记录到达这些字符串所需的最少操作步数。然后,对于每组输入数据,我们可以直接在记录的结果中进行查询,找到所需的最少操作步数。

下面是一个使用C语言实现的示例代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>#define MAX_STATES 100000// 定义状态结构体
typedef struct {char state[6];  // 保存状态的字符串int steps;      // 到达该状态所需的步数
} State;// 定义队列结构体
typedef struct {State data[MAX_STATES];int front;int rear;
} Queue;// 初始化队列
void initQueue(Queue *queue) {queue->front = queue->rear = 0;
}// 判断队列是否为空
int isQueueEmpty(Queue *queue) {return queue->front == queue->rear;
}// 入队
void enqueue(Queue *queue, State state) {queue->data[queue->rear] = state;queue->rear = (queue->rear + 1) % MAX_STATES;
}// 出队
State dequeue(Queue *queue) {State state = queue->data[queue->front];queue->front = (queue->front + 1) % MAX_STATES;return state;
}// 判断字符串是否已经存在于队列中
int isStateVisited(Queue *queue, char *state) {int i;for (i = queue->front; i != queue->rear; i = (i + 1) % MAX_STATES) {if (strcmp(queue->data[i].state, state) == 0) {return 1;}}return 0;
}// 进行广度优先搜索
void bfs() {Queue queue;initQueue(&queue);State startState;strcpy(startState.state, "12345");startState.steps = 0;enqueue(&queue, startState);int i, j;while (!isQueueEmpty(&queue)) {State currentState = dequeue(&queue);int steps = currentState.steps;if (steps > 3) {// 超过最大步数限制,不再继续搜索break;}// 尝试进行操作1:交换相邻的两个数字for (i = 0; i < 4; i++) {for (j = i + 1; j < 5; j++) {State nextState = currentState;char temp = nextState.state[i];nextState.state[i] = nextState.state[j];nextState.state[j] = temp;nextState.steps = steps + 1;if (!isStateVisited(&queue, nextState.state)) {enqueue(&queue, nextState);}}}// 尝试进行操作2:将一个数字加1for (i = 0; i < 5; i++) {State nextState = currentState;nextState.state[i] = (nextState.state[i] - '0' + 1) % 10 + '0';nextState.steps = steps + 1;if (!isStateVisited(&queue, nextState.state)) {enqueue(&queue, nextState);}}// 尝试进行操作3:将一个数字加倍for (i = 0; i < 5; i++) {State nextState = currentState;int num = nextState.state[i] - '0';nextState.state[i] = ((num * 2) % 10) + '0';nextState.steps = steps + 1;if (!isStateVisited(&queue, nextState.state)) {enqueue(&queue, nextState);}}}
}int main() {bfs();  // 预处理,进行广度优先搜索int T;scanf("%d", &T);while (T--) {char target[6];scanf("%s", target);Queue queue;initQueue(&queue);State startState;strcpy(startState.state, target);startState.steps = 0;enqueue(&queue, startState);int minSteps = -1;while (!isQueueEmpty(&queue)) {State currentState = dequeue(&queue);int steps = currentState.steps;if (strcmp(currentState.state, "12345") == 0) {// 找到目标状态minSteps = steps;break;}if (steps > 3) {// 超过最大步数限制,不再继续搜索break;}// 尝试进行操作1:交换相邻的两个数字for (i = 0; i < 4; i++) {for (j = i + 1; j < 5; j++) {State nextState = currentState;char temp = nextState.state[i];nextState.state[i] = nextState.state[j];nextState.state[j] = temp;nextState.steps = steps + 1;if (!isStateVisited(&queue, nextState.state)) {enqueue(&queue, nextState);}}}// 尝试进行操作2:将一个数字加1for (i = 0; i < 5; i++) {State nextState = currentState;nextState.state[i] = (nextState.state[i] - '0' + 1) % 10 + '0';nextState.steps = steps + 1;if (!isStateVisited(&queue, nextState.state)) {enqueue(&queue, nextState);}}// 尝试进行操作3:将一个数字加倍for (i = 0; i < 5; i++) {State nextState = currentState;int num = nextState.state[i] - '0';nextState.state[i] = ((num * 2) % 10) + '0';nextState.steps = steps + 1;if (!isStateVisited(&queue, nextState.state)) {enqueue(&queue, nextState);}}}printf("%d\n", minSteps);}return 0;
}

这个代码首先进行预处理,使用广度优先搜索找出所有可以从"12345"变换到的字符串,并记录到达这些字符串所需的最少操作步数。然后,对于每组输入数据,使用另一个队列进行广度优先搜索,找到从目标字符串到"12345"所需的最少操作步数,并输出结果。

请注意,这个代码使用了队列来实现广度优先搜索,并使用了一个布尔数组来记录已经访问过的状态,以避免重复搜索。同时,为了优化性能,在进行广度优先搜索时,限制了最大步数为3,超过这个步数的状态将不再考虑。

第2题:圣诞老人的礼物

圣诞节来临了,在城市A中圣诞老人准备分发糖果,现在有多箱不同的糖果,每箱糖果有自己的价值和重量,每箱糖果都可以拆分成任意散装组合带走。圣诞老人的驯鹿最多只能承受一定重量的糖果,请问圣诞老人最多能带走多大价值的糖果。
时间限制:1000
内存限制:65536
输入
第一行由两个部分组成,分别为糖果箱数正整数n(1 = n = 100),驯鹿能承受的最大重量正整数w(0 w 10000),两个数用空格隔开。其余n行每行对应一箱糖果,由两部分组成,分别为一箱糖果的价值正整数v和重量正整数w,中间用空格隔开。
输出
输出圣诞老人能带走的糖果的最大总价值,保留1位小数。输出为一行,以换行符结束。
样例输入
4 15
100 4
412 8
266 7
591 2
样例输出
1193.0

最容易实现的方法是使用贪心算法。下面是使用贪心算法的简单实现:

#include <stdio.h>#define MAX_N 100// 定义糖果的结构体
typedef struct {int value;int weight;
} Candy;// 贪心算法函数
double greedyAlgorithm(Candy candies[], int n, int maxWeight) {// 根据单位重量的价值进行排序for (int i = 0; i < n - 1; i++) {for (int j = 0; j < n - i - 1; j++) {double valuePerWeight1 = (double)candies[j].value / candies[j].weight;double valuePerWeight2 = (double)candies[j + 1].value / candies[j + 1].weight;if (valuePerWeight1 < valuePerWeight2) {// 交换糖果的位置Candy temp = candies[j];candies[j] = candies[j + 1];candies[j + 1] = temp;}}}double maxTotal = 0;int currentWeight = 0;for (int i = 0; i < n; i++) {if (currentWeight + candies[i].weight <= maxWeight) {// 将当前糖果全部带走maxTotal += candies[i].value;currentWeight += candies[i].weight;} else {// 部分带走当前糖果double remainingWeight = maxWeight - currentWeight;double remainingValue = (double)candies[i].value * remainingWeight / candies[i].weight;maxTotal += remainingValue;break;}}return maxTotal;
}int main() {int n, maxWeight;Candy candies[MAX_N];// 读取输入scanf("%d %d", &n, &maxWeight);for (int i = 0; i < n; i++) {scanf("%d %d", &candies[i].value, &candies[i].weight);}// 使用贪心算法double maxTotal = greedyAlgorithm(candies, n, maxWeight);// 输出结果printf("%.1lf\n", maxTotal);return 0;
}

这个方法的思路是先将糖果按照单位重量的价值进行排序,然后从价值最高的糖果开始,依次尽可能地带走糖果,直到达到驯鹿能够承受的最大重量。如果某个糖果无法完全带走,则部分带走该糖果。最后,将带走的糖果的总价值进行累加,即为圣诞老人能够带走的糖果的最大总价值。

第3题:忍者道具

忍者道具有很多种,苦无,飞镖,震爆弹。L君热衷于收集忍者道具,现在他有N个道具,每个道具的重量分别是C1、C2…CN。现在他想把这N个道具装到载重量为W的工具包里,请问他最少需要多少个工具包?
时间限制:1000
内存限制:65536
输入
第一行包含两个用空格隔开的整数,N和W。 接下来N行每行一个整数,其中第i+1行的整数表示第i个道具的重量Ci。
输出
输出一个整数,最少需要多少个工具包。
样例输入
5 1996
1
2
1994
12
29
样例输出
2
提示
对于100%的数据,1=N=18,1=Ci=W=10^8。

该题可以使用贪心算法来解决,下面是C语言代码:

#include <stdio.h>#define MAX_N 18int main() {int N, W;int weights[MAX_N];// 读取输入scanf("%d %d", &N, &W);for (int i = 0; i < N; i++) {scanf("%d", &weights[i]);}// 贪心算法求解int numBags = 0;int currentWeight = 0;for (int i = 0; i < N; i++) {if (currentWeight + weights[i] <= W) {// 当前工具包可以容纳该道具currentWeight += weights[i];} else {// 当前工具包无法容纳该道具,需要使用新的工具包numBags++;currentWeight = weights[i];}}// 若还有剩余道具未放入工具包,则需要额外的工具包if (currentWeight > 0) {numBags++;}// 输出结果printf("%d\n", numBags);return 0;
}

该算法的思路是按照道具的重量顺序进行遍历,如果当前工具包的载重量可以容纳当前道具,则将道具放入工具包中;否则,需要使用新的工具包来装载该道具。最后,如果还有剩余的道具未放入工具包,则需要额外的工具包。输出最少需要的工具包数量即为解。

第4题:求逆序对问题

给定N个数的序列a1,a2,…aN,定义一个数对(ai, aj)为“重要逆序对”的充要条件为 i j 且 ai 2aj。求给定序列中“重要逆序对”的个数。
时间限制:1000
内存限制:256000
输入
本题有多个测试点,每个测试点分为两行:第一行为序列中数字的个数N(1 ≤ N ≤ 200000),第二行为序列a1, a2 … aN(0 ≤a ≤ 10000000),由空格分开。N=0表示输入结束。
输出
每个测试点一行,输出一个整数,为给序列中“重要逆序对”的个数。
样例输入
10
0 9 8 7 6 5 4 3 2 1
0
样例输出
16
提示
请注意答案范围,如果使用printf输出long long类型,请用%lld

以下是使用分治技术来解决求逆序对问题的C语言代码:

#include <stdio.h>#define MAX_N 200000long long merge(int arr[], int temp[], int left, int mid, int right) {int i = left;     // 左子数组的起始索引int j = mid + 1;  // 右子数组的起始索引int k = left;     // 合并后数组的起始索引long long count = 0;  // 逆序对的个数// 统计逆序对的个数while (i <= mid && j <= right) {if (arr[i] > 2 * arr[j]) {count += (mid - i + 1);j++;} else {i++;}}// 归并排序并计算逆序对i = left;j = mid + 1;k = left;while (i <= mid && j <= right) {if (arr[i] <= arr[j]) {temp[k++] = arr[i++];} else {temp[k++] = arr[j++];}}while (i <= mid) {temp[k++] = arr[i++];}while (j <= right) {temp[k++] = arr[j++];}for (i = left; i <= right; i++) {arr[i] = temp[i];}return count;
}long long mergeSort(int arr[], int temp[], int left, int right) {long long count = 0;if (left < right) {int mid = (left + right) / 2;count += mergeSort(arr, temp, left, mid);count += mergeSort(arr, temp, mid + 1, right);count += merge(arr, temp, left, mid, right);}return count;
}int main() {int N;int arr[MAX_N];int temp[MAX_N];while (1) {// 读取输入scanf("%d", &N);if (N == 0) {break;}for (int i = 0; i < N; i++) {scanf("%d", &arr[i]);}// 使用分治技术求解逆序对个数long long count = mergeSort(arr, temp, 0, N - 1);// 输出结果printf("%lld\n", count);}return 0;
}

该算法使用归并排序的思想,在归并排序的过程中统计逆序对的个数。在归并的过程中,通过比较左子数组和右子数组的元素来统计逆序对的个数,并将左子数组和右子数组合并成一个有序数组。最后,返回逆序对的个数作为解。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Qt应用开发(基础篇)——进度条 QProgressBar

一、前言 QProgressBar类继承于QWidget&#xff0c;是一个提供了横向或者纵向进度条的小部件。 QProgressBar进度条一般用来显示用户某操作的进度&#xff0c;比如烧录、导入、导出、下发、上传、加载等这些需要耗时和分包的概念&#xff0c;让用户知道程序还在正常的执行中。 …

Git操作

Git 操作方法 Git 是一个分布式版本控制系统&#xff0c;用于管理项目的源代码。 gitee新建仓库提示如下 具体介绍看下面 1. 创建仓库 初始化本地仓库 使用以下命令在本地目录中初始化一个新的 Git 仓库&#xff1a; git init克隆远程仓库 使用以下命令克隆一个远程仓库…

java自动登录 selenium 自动登录并获取cookie

选择操作网页 我用的edge&#xff0c;谷歌我的版本太高没有对应的驱动… 下载Edge的驱动程序&#xff0c;直接解压就好里面只有一个.exe文件 https://developer.microsoft.com/en-us/microsoft-edge/tools/webdriver/ 复制即用&#xff0c;看注释 import com.alibaba.fastjs…

我们的第一个 Qt 窗口程序

Qt 入门实战教程&#xff08;目录&#xff09; Windows Qt 5.12.10下载与安装 为何使用Qt Creator开发QT 本文介绍用Qt自带的集成开发工具Qt Creator创建Qt默认的窗口程序。 本文不需要你另外安装Visual Studio 2022这样的集成开发环境&#xff0c;也不需要你再在Visual St…

Redis.conf 配置文件详解

1、units 单位 配置大小单位&#xff0c;开头定义了一些基本的度量单位&#xff0c;只支持 bytes&#xff0c;不支持bit&#xff0c;并且对大小写 不敏感。 2、INCLUDES 包含 类似于 Spring 配置文件&#xff0c;可以通过 includes 包含&#xff0c;redis.conf 可以作为总文件…

JVM运行时数据区

文章目录 JVM内存结构图1、运行时数据区域JDK 1.7JDK 1.81. 线程栈&#xff08;虚拟机栈&#xff09;2. 本地方法栈3. 程序计数器4. 方法区&#xff08;元空间&#xff09;5. 堆6、运行时常量池&#xff08;Runtime Constant Pool&#xff09;7、直接内存&#xff08;Direct Me…

QOpenGLWidget绘制实时图像

initializeGL()函数&#xff1a; initializeOpenGLFunctions();//创建VBO和VAO对象&#xff0c;并赋予IDglGenVertexArrays(1, &VAO);glGenBuffers(1, &VBO);//绑定VBO和VAO对象glBindVertexArray(VAO);glBindBuffer(GL_ARRAY_BUFFER, VBO);//为当前绑定到target的缓冲…

如何将Word中的中文数字转化为阿拉伯数字

例如这种情况&#xff1a; 需要把这些汉字数字改为阿拉伯数字。 步骤1&#xff1a;在任意位置输入“第章”&#xff0c;然后把光标放到“第”和“章”的中间&#xff0c;然后ctrlf9插入域&#xff0c;在域里面输入 autonum&#xff0c;然后按altf9 显示域值。 按下altF9后 第 …

MySQL怎样删除重复数据,只保留一条?

在实际工作开发过程中&#xff0c;常常会遇到数据库表中存在多条数据重复了&#xff0c;此时我们需要删除重复数据&#xff0c;只保留其中一条有效的数据&#xff1b; 针对这种场景&#xff0c;我们用SQL语句该怎么实现呢&#xff1f; 数据准备 建表语句&#xff1a; DROP …

.ssh文件夹下缺失known_hosts文件

.ssh文件夹下缺失known_hosts文件 先确认工蜂或github 添加了git生成的密钥 然后 桌面打开git bash 1、执行ssh -T gitgitlab.com 2、输入yes

kafka架构和原理详解

Apache Kafka 是一个分布式流数据平台,用于高吞吐量、持久性、可扩展的发布和订阅消息。它具有高度的可靠性,被广泛用于构建实时数据流处理、日志收集和数据管道等应用。 基本架构 1. 主题(Topic): 主题是消息的逻辑分类生产者将消息发布到特定的主题中,而消费者可以订阅…

ssm+vue海鲜自助餐厅系统源码和论文

ssmvue海鲜自助餐厅系统源码和论文068 开发工具&#xff1a;idea 数据库mysql5.7 数据库链接工具&#xff1a;navcat,小海豚等 技术&#xff1a;ssm 摘 要 网络技术和计算机技术发展至今&#xff0c;已经拥有了深厚的理论基础&#xff0c;并在现实中进行了充分运用&…

基于PID优化和矢量控制装置的四旋翼无人机(MatlabSimulink实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

嬴图Ultipa | 一文了解关于图数据库的一点儿干货

本篇包括以下内容点&#xff1a; 数据库主要技术分类 图是什么&#xff1f; 图的模式 图数据库 VS.关系型数据库 图数据库VS.其他NOSQL的对比 并非所有的图数据库都一样&#xff01; 根据Gartner预测&#xff0c;“到2025年&#xff0c;使用图技术进行数据和分析创新…

C# 生成唯一ID

1.首先通过nuget安装yitter.idgenerator 下面的三行代码搞定

数据结构 day1

1>x.mind 2>间接定义结构体数组&#xff0c;进行4种方式的定义和初始化 3>定义结构体存储10辆车&#xff08;车的信息&#xff1a;品牌、单价、颜色&#xff09; 1.定义函数&#xff0c;实现循环输入 2.定义函数&#xff0c;实现排序 3.定义函数&#xff0c;计算红色车…

树莓派3b无屏幕登录

如果要无屏登录&#xff0c;烧写时最好设置&#xff0c;勾选WIFI &#xff0c;登录密码&#xff0c;和SSH 树莓派操作系统下载地址 树莓派资源下载 | 树莓派实验室 无屏幕无键盘登录&#xff1a;新版中可能要先SSH登录&#xff0c;然后才能在RASPI-CONFIG中打开串口控制台 登录…

【Axure原型分享】能统计中英文字数的多行输入框

今天和大家分享能统计中英文字数的多行输入框的原型模板&#xff0c;在输入框里输入内容后&#xff0c;能够动态根据输入框的内容&#xff0c;统计出字符数量&#xff0c;包括总字数、中文字数、英文字数、数字字数、其他标点符号的字数&#xff0c;具体效果可以观看下方视频或…

2023-08-29 LeetCode(带因子的二叉树)

2023-08-29每日一题 一、题目编号 823. 带因子的二叉树二、题目链接 点击跳转到题目位置 三、题目描述 给出一个含有不重复整数元素的数组 arr &#xff0c;每个整数 arr[i] 均大于 1。 用这些整数来构建二叉树&#xff0c;每个整数可以使用任意次数。其中&#xff1a;每…

postgresql-字符函数

postgresql-字符函数 字符串连接字符与编码字符串长度大小写转换子串查找与替换截断与填充字符串格式化MD5 值字符串拆分字符串反转 字符串连接 concat(str, …)函数用于连接字符串&#xff0c;并且忽略其中的 NULL 参数&#xff1b;concat_ws(sep, str, …) 函数使用指定分隔…