C/C++编程(1~8级)全部真题・点这里
第1题:二叉树的深度
给定一棵二叉树,求该二叉树的深度
二叉树深度定义:从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的节点个数为树的深度
时间限制:1000
内存限制:65535
输入
第一行是一个整数n,表示二叉树的结点个数。二叉树结点编号从1到n,根结点为1,n <= 10 接下来有n行,依次对应二叉树的n个节点。 每行有两个整数,分别表示该节点的左儿子和右儿子的节点编号。如果第一个(第二个)数为-1则表示没有左(右)儿子
输出
输出一个整型数,表示树的深度
样例输入
3
2 3
-1 -1
-1 -1
样例输出
2
以下是使用C语言编写的解决方案:
#include <stdio.h>
#include <stdlib.h>
typedef struct Node {
int value;
struct Node* left;
struct Node* right;
} Node;
int maxDepth(Node* root) {
if (root == NULL) {
return 0;
}
int leftDepth = maxDepth(root->left);
int rightDepth = maxDepth(root->right);
return (leftDepth > rightDepth) ? (leftDepth + 1) : (rightDepth + 1);
}
Node* createNode(int value) {
Node* newNode = (Node*)malloc(sizeof(Node));
newNode->value = value;
newNode->left = NULL;
newNode->right = NULL;
return newNode;
}
Node* buildTree(int n) {
Node** nodes = (Node**)malloc((n + 1) * sizeof(Node*));
for (int i = 1; i <= n; i++) {
nodes[i] = createNode(i);
}
for (int i = 1; i <= n; i++) {
int left, right;
scanf("%d %d", &left, &right);
if (left != -1) {
nodes[i]->left = nodes[left];
}
if (right != -1) {
nodes[i]->right = nodes[right];
}
}
Node* root = nodes[1];
free(nodes);
return root;
}
int main() {
int n;
scanf("%d", &n);
Node* root = buildTree(n);
int depth = maxDepth(root);
printf("%d\n", depth);
free(root);
return 0;
}
这段代码实现了二叉树的构建和计算深度。
首先,通过createNode
函数创建一个具有给定值的新节点。
然后,buildTree
函数根据输入的信息构建二叉树。它首先创建一个节点数组,其中索引从1到n对应于二叉树的节点编号。然后,它遍历n行输入,将每个节点的左儿子和右儿子与相应的节点连接起来。
接下来,maxDepth
函数使用递归方式计算二叉树的深度。如果节点为空,说明到达了叶节点的子节点,返回0。否则,递归计算左子树和右子树的深度,并返回较大的深度加1。
最后,将深度输出到屏幕上。
第2题:迷宫
一天Extense在森林里探险的时候不小心走入了一个迷宫,迷宫可以看成是由n * n的格点组成,每个格点只有2种状态,.和#,前者表示可以通行后者表示不能通行。同时当Extense处在某个格点时,他只能移动到东南西北(或者说上下左右)四个方向之一的相邻格点上,Extense想要从点A走到点B,问在不走出迷宫的情况下能不能办到。如果起点或者终点有一个不能通行(为#),则看成无法办到。
时间限制:3000
内存限制:65536
输入
第1行是测试数据的组数k,后面跟着k组输入。每组测试数据的第1行是一个正整数n (1 <= n <= 100),表示迷宫的规模是n * n的。接下来是一个n * n的矩阵,矩阵中的元素为.或者#。再接下来一行是4个整数ha, la, hb, lb,描述A处在第ha行, 第la列,B处在第hb行, 第lb列。注意到ha, la, hb, lb全部是从0开始计数的。
输出
k行,每行输出对应一个输入。能办到则输出“YES”,否则输出“NO”。
样例输入
2
3
.##
…#
#…
0 0 2 2
5
…
###.#
…#…
###…
…#.
0 0 4 0
样例输出
YES
NO
以下是一个使用C语言编写的解决方案:
#include <stdio.h>
#define MAX_SIZE 100
// 定义迷宫的结构体
typedef struct {
int n; // 迷宫的规模
char grid[MAX_SIZE][MAX_SIZE]; // 迷宫的格点
} Maze;
// 初始化迷宫
void initMaze(Maze *maze, int n) {
maze->n = n;
}
// 读取迷宫的格点
void readGrid(Maze *maze) {
int i, j;
for (i = 0; i < maze->n; i++) {
for (j = 0; j < maze->n; j++) {
scanf(" %c", &maze->grid[i][j]);
}
}
}
// 判断一个格点是否有效
int isValid(int x, int y, Maze *maze) {
if (x >= 0 && x < maze->n && y >= 0 && y < maze->n && maze->grid[x][y] == '.')
return 1;
else
return 0;
}
// 在迷宫中搜索路径
int searchPath(int x, int y, Maze *maze) {
if (!isValid(x, y, maze)) // 如果当前格点无效,则返回0
return 0;
if (x == maze->n - 1 && y == maze->n - 1) // 如果当前格点是终点,则返回1
return 1;
maze->grid[x][y] = '#'; // 将当前格点标记为已访问
// 递归搜索四个方向的相邻格点
if (searchPath(x + 1, y, maze) || searchPath(x - 1, y, maze) || searchPath(x, y + 1, maze) || searchPath(x, y - 1, maze))
return 1;
return 0;
}
int main() {
int k, i;
scanf("%d", &k); // 读取测试数据的组数
for (i = 0; i < k; i++) {
int n, ha, la, hb, lb;
scanf("%d", &n); // 读取迷宫的规模
Maze maze;
initMaze(&maze, n); // 初始化迷宫
readGrid(&maze); // 读取迷宫的格点
scanf("%d %d %d %d", &ha, &la, &hb, &lb); // 读取起点和终点坐标
if (maze.grid[ha][la] == '#' || maze.grid[hb][lb] == '#') {
printf("NO\n"); // 起点或终点无效
} else {
if (searchPath(ha, la, &maze))
printf("YES\n"); // 能到达终点
else
printf("NO\n"); // 无法到达终点
}
}
return 0;
}
这个程序首先定义了一个Maze
结构体,用于表示迷宫的信息,包括规模和格点的状态。然后通过initMaze
函数初始化迷宫,通过readGrid
函数读取迷宫的格点。
在searchPath
函数中,使用递归的方式进行深度优先搜索,搜索四个方向的相邻格点,如果找到终点则返回1,否则返回0。
在main
函数中,根据输入的测试数据的组数进行循环。每次循环中,读取迷宫的规模、格点、起点和终点的坐标,并调用searchPath
函数判断是否能够到达终点,并输出结果。
请注意,该程序假设输入的数据是合法的,即起点和终点都在迷宫的范围内,并且起点和终点的格点都是可通行的。如果输入的数据不符合要求,程序可能会出错。在实际应用中,建议添加错误处理代码来处理异常情况。
第3题:Sequence
给定m个数字序列,每个序列包含n个非负整数。我们从每一个序列中选取一个数字组成一个新的序列,显然一共可以构造出nm个新序列。接下来我们对每一个新的序列中的数字进行求和,一共会得到nm个和,请找出最小的n个和
时间限制:3000
内存限制:65536
输入
输入的第一行是一个整数T,表示测试用例的数量,接下来是T个测试用例的输入 每个测试用例输入的第一行是两个正整数m(0 < m <= 100)和n(0 < n <= 2000),然后有m行,每行有n个数,数字之间用空格分开,表示这m个序列 序列中的数字不会大于10000
输出
对每组测试用例,输出一行用空格隔开的数,表示最小的n个和
样例输入
1
2 3
1 2 3
2 2 3
样例输出
3 3 4
以下是一个使用C语言编写的解决方案:
#include <stdio.h>
#include <stdlib.h>
// 比较函数,用于qsort排序
int compare(const void *a, const void *b) {
return (*(int *)a - *(int *)b);
}
int main() {
int T;
scanf("%d", &T); // 读取测试用例的数量
while (T--) {
int m, n;
scanf("%d %d", &m, &n); // 读取m和n
int i, j;
int *sequence = (int *)malloc(m * n * sizeof(int)); // 动态分配内存存储序列
int *sums = (int *)malloc(m * n * sizeof(int)); // 动态分配内存存储和
for (i = 0; i < m; i++) {
for (j = 0; j < n; j++) {
scanf("%d", &sequence[i * n + j]); // 读取序列中的数字
}
}
// 计算和并存储在sums数组中
for (i = 0; i < m; i++) {
for (j = 0; j < n; j++) {
sums[i * n + j] = sequence[i * n + j];
if (i > 0) {
sums[i * n + j] += sums[(i - 1) * n + j];
}
if (j > 0) {
sums[i * n + j] += sums[i * n + j - 1];
}
if (i > 0 && j > 0) {
sums[i * n + j] -= sums[(i - 1) * n + j - 1];
}
}
}
// 使用快速排序对和进行排序
qsort(sums, m * n, sizeof(int), compare);
// 输出最小的n个和
for (i = 0; i < n; i++) {
printf("%d ", sums[i]);
}
printf("\n");
free(sequence); // 释放内存
free(sums);
}
return 0;
}
该程序首先读取测试用例的数量,并通过循环处理每个测试用例。
在每个测试用例中,首先读取m和n,然后动态分配内存以存储序列和和结果。接下来,使用两层循环读取每个序列的数字,并计算和,将和存储在sums数组中。在计算和时,如果当前位置的行数大于0,则加上上一行的和;如果当前位置的列数大于0,则加上前一列的和;如果当前位置的行数和列数都大于0,则减去左上角的和,以避免重复计算。
之后,使用快速排序(qsort)对和进行排序。最后,输出最小的n个和。
请注意,该程序假设输入的数据是合法的,并且m和n的值在有效范围内。如果输入的数据不符合要求,程序可能会出错。在实际应用中,建议添加错误处理代码来处理异常情况。
第4题:priority queue练习题
我们定义一个正整数a比正整数b优先的含义是:
*a的质因数数目(不包括自身)比b的质因数数目多;
*当两者质因数数目相等时,数值较大者优先级高。
现在给定一个容器,初始元素数目为0,之后每次往里面添加10个元素,每次添加之后,要求输出优先级最高与最低的元素,并把该两元素从容器中删除。
时间限制:2500
内存限制:131072
输入
第一行: num (添加元素次数,num <= 30)
下面10*num行,每行一个正整数n(n < 10000000).
输出
每次输入10个整数后,输出容器中优先级最高与最低的元素,两者用空格间隔。
样例输入
1
10 7 66 4 5 30 91 100 8 9
样例输出
66 5
以下是一个使用C语言编写的解决方案:
#include <stdio.h>
#include <stdlib.h>
#define MAX_SIZE 10
#define MAX_PRIME_FACTORS 100
// 结点结构体定义
typedef struct {
int value; // 数值
int prime_factors; // 质因数数目
} Node;
// 优先队列结构体定义
typedef struct {
Node heap[MAX_SIZE]; // 存储结点的数组
int size; // 当前队列的大小
} PriorityQueue;
// 初始化优先队列
void initQueue(PriorityQueue *queue) {
queue->size = 0;
}
// 交换两个结点
void swap(Node *a, Node *b) {
Node temp = *a;
*a = *b;
*b = temp;
}
// 上浮操作
void siftUp(PriorityQueue *queue, int index) {
if (index == 0) // 已经是根节点,不需要上浮
return;
int parent = (index - 1) / 2;
if (queue->heap[parent].prime_factors < queue->heap[index].prime_factors ||
(queue->heap[parent].prime_factors == queue->heap[index].prime_factors &&
queue->heap[parent].value < queue->heap[index].value)) {
swap(&queue->heap[parent], &queue->heap[index]);
siftUp(queue, parent);
}
}
// 下沉操作
void siftDown(PriorityQueue *queue, int index) {
int leftChild = index * 2 + 1;
int rightChild = index * 2 + 2;
int max = index;
if (leftChild < queue->size &&
(queue->heap[leftChild].prime_factors > queue->heap[max].prime_factors ||
(queue->heap[leftChild].prime_factors == queue->heap[max].prime_factors &&
queue->heap[leftChild].value > queue->heap[max].value))) {
max = leftChild;
}
if (rightChild < queue->size &&
(queue->heap[rightChild].prime_factors > queue->heap[max].prime_factors ||
(queue->heap[rightChild].prime_factors == queue->heap[max].prime_factors &&
queue->heap[rightChild].value > queue->heap[max].value))) {
max = rightChild;
}
if (max != index) {
swap(&queue->heap[max], &queue->heap[index]);
siftDown(queue, max);
}
}
// 入队操作
void enqueue(PriorityQueue *queue, int value) {
if (queue->size == MAX_SIZE) // 队列已满
return;
Node node;
node.value = value;
node.prime_factors = 0;
// 统计质因数数目
int i;
int temp = value;
for (i = 2; i * i <= temp; i++) {
if (temp % i == 0) {
node.prime_factors++;
while (temp % i == 0)
temp /= i;
}
}
if (temp > 1)
node.prime_factors++;
queue->heap[queue->size] = node;
siftUp(queue, queue->size);
queue->size++;
}
// 出队操作
int dequeue(PriorityQueue *queue) {
if (queue->size == 0) // 队列为空
return -1;
int value = queue->heap[0].value;
queue->size--;
queue->heap[0] = queue->heap[queue->size];
siftDown(queue, 0);
return value;
}
int main() {
int num;
scanf("%d", &num); // 读取添加元素次数
PriorityQueue queue;
initQueue(&queue); // 初始化优先队列
int i, j;
for (i = 0; i < num; i++) {
for (j = 0; j < MAX_SIZE; j++) {
int value;
scanf("%d", &value); // 读取元素值
enqueue(&queue, value); // 入队
}
int max = dequeue(&queue); // 出队优先级最高的元素
int min = dequeue(&queue); // 出队优先级最低的元素
printf("%d %d\n", max, min);
}
return 0;
}
该程序使用优先队列(最大堆)来实现。首先定义了结点结构体Node
,用来存储元素的数值和质因数数目。然后定义了优先队列结构体PriorityQueue
,包含一个存储结点的数组和当前队列的大小。
程序中实现了以下几个函数:
-
initQueue
:初始化优先队列。 -
swap
:交换两个结点。 -
siftUp
:上浮操作,用于调整结点位置以维持最大堆的性质。 -
siftDown
:下沉操作,用于调整结点位置以维持最大堆的性质。 -
enqueue
:入队操作,将元素插入到优先队列中。 -
dequeue
:出队操作,将优先级最高的元素从队列中删除并返回其值。
在主函数中,首先读取添加元素次数num
。然后通过循环,依次读取每次添加的10个整数,并调用enqueue
函数将它们加入到优先队列中。接着,循环中使用dequeue
函数分别从队列中删除优先级最高和最低的元素,并输出它们的值。
请注意,该程序假设输入的数据是合法的,并且每次添加的元素数量为10。如果输入的数据不符合要求,程序可能会出错。在实际应用中,建议添加错误处理代码来处理异常情况。