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

本文主要是介绍2023年09月 C/C++(八级)真题解析#中国电子学会#全国青少年软件编程等级考试,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在这里插入图片描述

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

第1题:最短路径问题

平面上有n个点(n<=100),每个点的坐标均在-10000~10000之间。其中的一些点之间有连线。
若有连线,则表示可从一个点到达另一个点,即两点间有通路,通路的距离为两点间的直线距离。现在的任务是找出从一点到另一点之间的最短路径。
时间限制:1000
内存限制:131072
输入
共n+m+3行,其中: 第一行为整数n。 第2行到第n+1行(共n行) ,每行两个整数x和y,描述了一个点的坐标。 第n+2行为一个整数m,表示图中连线的个数。 此后的m 行,每行描述一条连线,由两个整数i和j组成,表示第i个点和第j个点之间有连线。 最后一行:两个整数s和t,分别表示源点和目标点。
输出
仅一行,一个实数(保留两位小数),表示从s到t的最短路径长度。
样例输入
5
0 0
2 0
2 2
0 2
3 1
5
1 2
1 3
1 4
2 5
3 5
1 5
样例输出
3.41

下面是一个使用C语言解决最短路径问题的示例代码:

#include <stdio.h>
#include <math.h>#define MAX_POINTS 100typedef struct {int x;int y;
} Point;double distance(Point p1, Point p2) {int dx = p2.x - p1.x;int dy = p2.y - p1.y;return sqrt(dx * dx + dy * dy);
}double shortestPath(Point points[], int n, int connections[][2], int m, int source, int target) {double dist[MAX_POINTS];int visited[MAX_POINTS] = {0};int i, j;for (i = 0; i < n; i++) {dist[i] = INFINITY;}dist[source] = 0;for (i = 0; i < n - 1; i++) {int minIndex = -1;double minDist = INFINITY;for (j = 0; j < n; j++) {if (!visited[j] && dist[j] < minDist) {minIndex = j;minDist = dist[j];}}visited[minIndex] = 1;for (j = 0; j < m; j++) {int u = connections[j][0];int v = connections[j][1];double d = distance(points[u], points[v]);if (!visited[v] && dist[u] + d < dist[v]) {dist[v] = dist[u] + d;}}}return dist[target];
}int main() {int n, m;Point points[MAX_POINTS];int connections[MAX_POINTS][2];int source, target;int i;scanf("%d", &n);for (i = 0; i < n; i++) {scanf("%d %d", &points[i].x, &points[i].y);}scanf("%d", &m);for (i = 0; i < m; i++) {scanf("%d %d", &connections[i][0], &connections[i][1]);}scanf("%d %d", &source, &target);double shortestDist = shortestPath(points, n, connections, m, source - 1, target - 1);printf("%.2f\n", shortestDist);return 0;
}

解释:

首先,我们定义了一个Point结构体来表示点的坐标。

distance()函数用于计算两个点之间的直线距离。

shortestPath()函数实现了Dijkstra算法来找到最短路径的长度。它使用一个距离数组dist来保存每个点到源点的最短距离,visited数组用于标记已经访问过的点。在每一轮迭代中,它选择距离源点最近且未访问过的点作为当前点,然后更新与当前点相邻的点的最短距离。

main()函数中,我们首先读取输入数据,包括点的坐标、连线的信息以及源点和目标点的编号。

然后调用shortestPath()函数来计算最短路径的长度,并打印结果。

第2题:控制公司

有些公司是其他公司的部分拥有者,因为他们获得了其他公司发行的股票的一部分。例如,福特公司拥有马自达公司12%的股票。据说,如果至少满足了以下条件之一,公司A就可以控制公司B了:
l 公司A = 公司B。
l 公司A拥有大于50%的公司B的股票。
l 公司A控制K(K >= 1)个公司,记为C1, …, CK,每个公司Ci拥有xi%的公司B的股票,并且x1+ … + xK > 50%。(ps:A可以控制自己,即Ci可以为A)
你将被给予一系列的三对数(i,j,p),表明公司i拥有公司j的p%的股票。计算所有的数对(h,s),表明公司h控制公司s。
写一个程序读入三对数(i,j,p),并且找出所有的数对(h,s),使得公司h控制公司s。
时间限制:1000
内存限制:65536
输入
第一行: N,表明接下来三对数的数量。 第二行到第N+1行:每行三个整数作为一个三对数(i,j,p),如上文所述。 I,J≤100,N,P≤100
输出
输出零个或更多个的控制其他公司的公司。每行包括两个整数表明序号为第一个整数的公司控制了序号为第二个整数的公司。将输出的每行以第一个数字升序排列(并且第二个数字也升序排列来避免并列)。请不要输出控制自己的公司。
样例输入
3
1 2 80
2 3 80
3 1 20
样例输出
1 2
1 3
2 3

下面是一个使用C语言解决控制公司问题的示例代码:

#include <stdio.h>#define MAX_COMPANIES 100int ownership[MAX_COMPANIES][MAX_COMPANIES] = {0};
int controlled[MAX_COMPANIES][MAX_COMPANIES] = {0};
int n;void dfs(int company, int owner) {int i;for (i = 0; i < n; i++) {if (ownership[company][i] > 0 && controlled[owner][i] == 0) {controlled[owner][i] = 1;dfs(i, owner);}}
}int main() {scanf("%d", &n);int i, j, p;while (n--) {scanf("%d %d %d", &i, &j, &p);ownership[i - 1][j - 1] = p;}for (i = 0; i < MAX_COMPANIES; i++) {controlled[i][i] = 1;for (j = 0; j < MAX_COMPANIES; j++) {if (ownership[i][j] > 50) {controlled[i][j] = 1;dfs(j, i);}}}for (i = 0; i < MAX_COMPANIES; i++) {for (j = 0; j < MAX_COMPANIES; j++) {if (controlled[i][j] && i != j) {printf("%d %d\n", i + 1, j + 1);}}}return 0;
}

解释:

首先,我们定义了两个二维数组ownershipcontrolled,用于存储公司之间的股权关系和控制关系。

dfs()函数是一个深度优先搜索算法,用于遍历公司之间的股权关系,并更新控制关系。

main()函数中,我们首先从输入中读取公司之间的股权关系,并将其保存在ownership数组中。

然后,使用两个嵌套循环遍历所有公司,如果某个公司拥有超过50%的另一个公司的股权,则将其标记为控制关系,并调用dfs()函数来更新其他受控公司。

最后,我们遍历controlled数组,输出所有的控制关系。

第3题:发现它,抓住它

一个城市中有两个犯罪团伙A和B,你需要帮助警察判断任意两起案件是否是同一个犯罪团伙所为,警察所获得的信息是有限的。假设现在有N起案件(N<=100000),编号为1到N,每起案件由团伙A或团伙B所为。你将按时间顺序获得M条信息(M<=100000),这些信息分为两类:
1、D [a] [b]
其中[a]和[b]表示两起案件的编号,这条信息表明它们属于不同的团伙所为
2、A [a] [b]
其中[a]和[b]表示两起案件的编号,这条信息需要你回答[a]和[b]是否是同一个团伙所为
注意你获得信息的时间是有先后顺序的,在回答的时候只能根据已经接收到的信息做出判断。
时间限制:1000
内存限制:65536
输入
第一行是测试数据的数量T(1<=T<=20)。 每组测试数据的第一行包括两个数N和M,分别表示案件的数量和信息的数量,其后M行表示按时间顺序收到的M条信息。
输出
对于每条需要回答的信息,你需要输出一行答案。如果是同一个团伙所为,回答"In the same gang.“,如果不是,回答"In different gangs.”,如果不确定,回答”Not sure yet."。
样例输入
1
5 5
A 1 2
D 1 2
A 1 2
D 2 4
A 1 4
样例输出
Not sure yet.
In different gangs.
In the same gang.

下面是一个使用C语言解决判断案件团伙问题的示例代码:

#include <stdio.h>#define MAX_CASES 100000int gang[MAX_CASES];int find(int x) {if (gang[x] == x)return x;return gang[x] = find(gang[x]);
}void merge(int x, int y) {int fx = find(x);int fy = find(y);if (fx != fy)gang[fy] = fx;
}int main() {int T;scanf("%d", &T);while (T--) {int N, M;scanf("%d %d", &N, &M);// 初始化每个案件所属的团伙for (int i = 1; i <= N; i++)gang[i] = i;char op;int a, b;while (M--) {scanf(" %c %d %d", &op, &a, &b);if (op == 'A') {// 判断是否属于同一个团伙if (find(a) == find(b))printf("In the same gang.\n");elseprintf("In different gangs.\n");} else if (op == 'D') {// 合并两个团伙merge(a, b);}}}return 0;
}

解释:

首先,我们定义了一个整数数组gang,用于存储每个案件所属的团伙。

find()函数是一个递归的查找函数,用于找到某个案件所属的团伙的根节点。

merge()函数用于合并两个团伙,将其中一个团伙的根节点指向另一个团伙的根节点。

main()函数中,我们首先读取测试数据的数量T,然后开始处理每组测试数据。

对于每组测试数据,我们首先根据案件数量N初始化每个案件所属的团伙为自身。

然后,依次读取每条信息,并根据信息的类型进行相应的操作。如果是类型为A的信息,我们调用find()函数判断两个案件是否属于同一个团伙;如果是类型为D的信息,我们调用merge()函数合并两个团伙。

最后,根据判断的结果输出相应的答案。

第4题:最短路

给定一个n个点, m条边的有向图, 求从点S出发, 到其它所有点的最短路径.
时间限制:2000
内存限制:65536
输入
第一行一个整数T, 表示有T组数据 对于每组测试数据, 第一行三个整数n, m, S, 表示有n个点, m条边, 起点为S. 接下来m行, 每行三个整数x, y, z, 代表从x到y有长度为z的边 点的编号从1到n T <= 10, n <= 10000, m <= 20000, |z| <= 10000. 所有数据的n之和 <= 30000, 所有数据的m之和 <= 60000.
输出
对于每组数据: 如果从S点出发可以走入负圈 (即到某些点的最短路径可以无限小), 那么输出一行Error. 否则, 输出一行用空格分隔的n个整数, 其中第i个整数表示从S点到i点的最短路长度. 如果从S点无法到达i点, 则第i个输出为”null”.
样例输入
4
5 7 1
1 2 3
2 3 4
3 4 8
1 3 9
4 5 1
1 4 5
1 5 10
4 4 1
1 2 -4
2 3 8
1 3 5
3 4 0
3 3 2
1 2 -3
2 3 -4
3 1 6
4 2 1
1 2 1
3 4 2
样例输出
0 3 7 5 6
0 -4 4 4
Error
0 1 null null

下面是一个使用C语言解决最短路径问题的示例代码,使用Dijkstra算法:

#include <stdio.h>
#include <stdbool.h>
#include <limits.h>#define MAX_NODES 10001
#define MAX_EDGES 60001
#define INF INT_MAXtypedef struct {int node;int cost;
} Edge;typedef struct {Edge edges[MAX_EDGES];int count;
} AdjList;AdjList graph[MAX_NODES];
int dist[MAX_NODES];void dijkstra(int start, int n) {bool visited[MAX_NODES];int i, j;for (i = 1; i <= n; i++) {dist[i] = INF;visited[i] = false;}dist[start] = 0;for (i = 1; i <= n; i++) {int u = -1;for (j = 1; j <= n; j++) {if (!visited[j] && (u == -1 || dist[j] < dist[u])) {u = j;}}if (dist[u] == INF) {break;}visited[u] = true;for (j = 0; j < graph[u].count; j++) {int v = graph[u].edges[j].node;int cost = graph[u].edges[j].cost;if (dist[u] + cost < dist[v]) {dist[v] = dist[u] + cost;}}}
}int main() {int T;scanf("%d", &T);while (T--) {int n, m, S;scanf("%d %d %d", &n, &m, &S);int i;for (i = 1; i <= n; i++) {graph[i].count = 0;}for (i = 0; i < m; i++) {int x, y, z;scanf("%d %d %d", &x, &y, &z);graph[x].edges[graph[x].count].node = y;graph[x].edges[graph[x].count].cost = z;graph[x].count++;}dijkstra(S, n);for (i = 1; i <= n; i++) {if (dist[i] == INF) {printf("null ");} else {printf("%d ", dist[i]);}}printf("\n");}return 0;
}

解释:

首先,我们定义了一个结构体Edge,用于表示图中的边,包括目标节点和边的权重。

然后,我们定义了一个结构体AdjList,用于表示邻接表,其中包含一个Edge类型的数组以及边的数量。

我们使用邻接表数组graph来表示图,每个节点对应一个邻接表。

dijkstra()函数是一个实现Dijkstra算法的函数,用于计算从起点出发到其他所有点的最短路径。

main()函数中,我们首先读取测试数据的数量T,然后开始处理每组测试数据。

对于每组测试数据,我们首先根据节点数量n初始化图的邻接表。

然后,依次读取每条边的信息,并将其添加到对应节点的邻接表中。

接下来,我们调用dijkstra()函数计算从起点S出发到其他所有点的最短路径。

最后,我们根据最短路径的计算结果输出每个节点的最短路径长度或"null"。

这篇关于2023年09月 C/C++(八级)真题解析#中国电子学会#全国青少年软件编程等级考试的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/264242

相关文章

C++中unordered_set哈希集合的实现

《C++中unordered_set哈希集合的实现》std::unordered_set是C++标准库中的无序关联容器,基于哈希表实现,具有元素唯一性和无序性特点,本文就来详细的介绍一下unorder... 目录一、概述二、头文件与命名空间三、常用方法与示例1. 构造与析构2. 迭代器与遍历3. 容量相关4

Java中Redisson 的原理深度解析

《Java中Redisson的原理深度解析》Redisson是一个高性能的Redis客户端,它通过将Redis数据结构映射为Java对象和分布式对象,实现了在Java应用中方便地使用Redis,本文... 目录前言一、核心设计理念二、核心架构与通信层1. 基于 Netty 的异步非阻塞通信2. 编解码器三、

C++中悬垂引用(Dangling Reference) 的实现

《C++中悬垂引用(DanglingReference)的实现》C++中的悬垂引用指引用绑定的对象被销毁后引用仍存在的情况,会导致访问无效内存,下面就来详细的介绍一下产生的原因以及如何避免,感兴趣... 目录悬垂引用的产生原因1. 引用绑定到局部变量,变量超出作用域后销毁2. 引用绑定到动态分配的对象,对象

Java HashMap的底层实现原理深度解析

《JavaHashMap的底层实现原理深度解析》HashMap基于数组+链表+红黑树结构,通过哈希算法和扩容机制优化性能,负载因子与树化阈值平衡效率,是Java开发必备的高效数据结构,本文给大家介绍... 目录一、概述:HashMap的宏观结构二、核心数据结构解析1. 数组(桶数组)2. 链表节点(Node

Java AOP面向切面编程的概念和实现方式

《JavaAOP面向切面编程的概念和实现方式》AOP是面向切面编程,通过动态代理将横切关注点(如日志、事务)与核心业务逻辑分离,提升代码复用性和可维护性,本文给大家介绍JavaAOP面向切面编程的概... 目录一、AOP 是什么?二、AOP 的核心概念与实现方式核心概念实现方式三、Spring AOP 的关

Java 虚拟线程的创建与使用深度解析

《Java虚拟线程的创建与使用深度解析》虚拟线程是Java19中以预览特性形式引入,Java21起正式发布的轻量级线程,本文给大家介绍Java虚拟线程的创建与使用,感兴趣的朋友一起看看吧... 目录一、虚拟线程简介1.1 什么是虚拟线程?1.2 为什么需要虚拟线程?二、虚拟线程与平台线程对比代码对比示例:三

一文解析C#中的StringSplitOptions枚举

《一文解析C#中的StringSplitOptions枚举》StringSplitOptions是C#中的一个枚举类型,用于控制string.Split()方法分割字符串时的行为,核心作用是处理分割后... 目录C#的StringSplitOptions枚举1.StringSplitOptions枚举的常用

Python函数作用域与闭包举例深度解析

《Python函数作用域与闭包举例深度解析》Python函数的作用域规则和闭包是编程中的关键概念,它们决定了变量的访问和生命周期,:本文主要介绍Python函数作用域与闭包的相关资料,文中通过代码... 目录1. 基础作用域访问示例1:访问全局变量示例2:访问外层函数变量2. 闭包基础示例3:简单闭包示例4

MyBatis延迟加载与多级缓存全解析

《MyBatis延迟加载与多级缓存全解析》文章介绍MyBatis的延迟加载与多级缓存机制,延迟加载按需加载关联数据提升性能,一级缓存会话级默认开启,二级缓存工厂级支持跨会话共享,增删改操作会清空对应缓... 目录MyBATis延迟加载策略一对多示例一对多示例MyBatis框架的缓存一级缓存二级缓存MyBat

前端缓存策略的自解方案全解析

《前端缓存策略的自解方案全解析》缓存从来都是前端的一个痛点,很多前端搞不清楚缓存到底是何物,:本文主要介绍前端缓存的自解方案,文中通过代码介绍的非常详细,需要的朋友可以参考下... 目录一、为什么“清缓存”成了技术圈的梗二、先给缓存“把个脉”:浏览器到底缓存了谁?三、设计思路:把“发版”做成“自愈”四、代码