C/C++编程(1~8级)全部真题・点这里
第1题:有多少种二叉树
输入n(1<n<13),求n个结点的二叉树有多少种形态
时间限制:1000
内存限制:65536
输入
整数n
输出
答案
样例输入
3
样例输出
5
这个问题可以使用动态规划的方法来解决。我们可以定义一个数组dp
,其中dp[i]
表示有i
个节点时的二叉树的种数。根据二叉树的性质,我们可以知道一个二叉树的种数取决于其左子树和右子树的种数。
具体的动态规划递推关系如下:
对于i
个节点的二叉树,我们可以选择一个节点作为根节点,将其左边的节点构成左子树,右边的节点构成右子树。根据这个划分,可以得到以下关系:
dp[i] = dp[0] * dp[i-1] + dp[1] * dp[i-2] + ... + dp[i-1] * dp[0]
其中,dp[j]
表示有j
个节点构成的二叉树的种数。
根据上述递推关系,我们可以通过动态规划的方式计算出dp[n]
,即有n
个节点的二叉树的种数。
下面是使用C语言实现的代码:
#include <stdio.h>
long long int countBinaryTrees(int n) {
long long int dp[n + 1];
dp[0] = 1;
dp[1] = 1;
for (int i = 2; i <= n; i++) {
dp[i] = 0;
for (int j = 0; j < i; j++) {
dp[i] += dp[j] * dp[i - j - 1];
}
}
return dp[n];
}
int main() {
int n;
scanf("%d", &n);
long long int result = countBinaryTrees(n);
printf("%lld\n", result);
return 0;
}
该代码中使用了一个数组dp
来保存中间结果,避免重复计算。时间复杂度为O(n^2),空间复杂度为O(n)。请注意,由于给定的n
的范围较小,因此使用整型变量和long long int
类型即可满足要求。如果需要支持更大范围的n
,可以考虑使用高精度整数库。
第2题:城堡问题
1 2 3 4 5 6 7
#############################
1 # | # | # | | #
#####—#####—#—#####—#
2 # # | # # # # #
#—#####—#####—#####—#
3 # | | # # # # #
#—#########—#####—#—#
4 # # | | | | # #
#############################
(图 1)
# = Wall
| = No wall
- = No wall
图1是一个城堡的地形图。请你编写一个程序,计算城堡一共有多少房间,最大的房间有多大。城堡被分割成m×n(m≤50,n≤50)个方块,每个方块可以有0~4面墙。
时间限制:1000
内存限制:65536
输入
程序从标准输入设备读入数据。第1、2行每行1个整数,分别是南北向、东西向的方块数。在接下来的输入行里,每个方块用一个数字(0≤p≤50)描述。用一个数字表示方块周围的墙,1表示西墙,2表示北墙,4表示东墙,8表示南墙。每个方块用代表其周围墙的数字之和表示。城堡的内墙被计算两次,方块(1,1)的南墙同时也是方块(2,1)的北墙。输入的数据保证城堡至少有两个房间。
输出
输出2行,每行一个数,表示城堡的房间数、城堡中最大房间所包括的方块数。结果显示在标准输出设备上。
样例输入
4
7
11 6 11 6 3 10 6
7 9 6 13 5 15 5
1 10 12 7 13 7 5
13 11 10 8 10 12 13
样例输出
5
9
这个问题可以使用深度优先搜索(DFS)算法来解决。我们可以遍历城堡的每个房间,对于每个未访问过的房间,进行深度优先搜索,统计房间的数量和最大房间的大小。
具体的算法步骤如下:
-
定义一个二维数组
visited
用于记录房间的访问状态,初始化为0。 -
定义变量
roomCount
用于记录房间数量,初始化为0。 -
定义变量
maxRoomSize
用于记录最大房间的大小,初始化为0。 -
对于城堡的每个房间,如果该房间未被访问过,则进行深度优先搜索:
-
将当前房间标记为已访问(设置
visited
数组对应位置为1)。 -
增加
roomCount
的值。 -
计算当前房间的大小,即从当前房间开始的连通区域的大小,使用递归实现:
-
统计当前房间的大小,并更新
maxRoomSize
的值。 -
对当前房间的四个方向进行判断,如果该方向没有墙且相邻房间未被访问过,则继续递归搜索该相邻房间。
-
- 输出
roomCount
和maxRoomSize
的值。
下面是使用C语言实现的代码:
#include <stdio.h>
#define MAX_SIZE 50
int castle[MAX_SIZE][MAX_SIZE];
int visited[MAX_SIZE][MAX_SIZE];
int dfs(int row, int col) {
if (visited[row][col])
return 0;
visited[row][col] = 1;
int size = 1;
if (castle[row][col] % 2 == 0) // 没有西墙
size += dfs(row, col - 1);
if (castle[row][col] % 4 >= 2) // 没有北墙
size += dfs(row - 1, col);
if (castle[row][col] % 8 >= 4) // 没有东墙
size += dfs(row, col + 1);
if (castle[row][col] >= 8) // 没有南墙
size += dfs(row + 1, col);
return size;
}
void findLargestRoom(int m, int n, int* roomCount, int* maxRoomSize) {
*roomCount = 0;
*maxRoomSize = 0;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
visited[i][j] = 0;
}
}
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (!visited[i][j]) {
(*roomCount)++;
int size = dfs(i, j);
if (size > *maxRoomSize)
*maxRoomSize = size;
}
}
}
}
int main() {
int m, n;
scanf("%d%d", &m, &n);
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
scanf("%d", &castle[i][j]);
}
}
int roomCount, maxRoomSize;
findLargestRoom(m, n, &roomCount, &maxRoomSize);
printf("%d\n%d\n", roomCount, maxRoomSize);
return 0;
}
该代码中,castle
数组表示城堡的地形图,visited
数组用于记录房间的访问状态。dfs
函数实现了深度优先搜索,计算从某个房间开始的连通区域的大小。findLargestRoom
函数遍历城堡的每个房间,对于每个未访问过的房间进行深度优先搜索,统计房间的数量和最大房间的大小。最后,输出房间数量和最大房间的大小。
该代码的时间复杂度为O(mn),其中m和n分别是城堡的南北向和东西向方块数。空间复杂度为O(mn),用于存储visited
数组。请注意,题目给定的城堡大小范围较小,因此使用二维数组存储数据是可行的。如果需要支持更大范围的城堡,可以考虑使用动态分配的二维数组或其他数据结构来存储数据。
第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 <stdio.h>
#include <stdlib.h>
typedef struct {
int weight;
struct Node* next;
} Node;
Node* stack = NULL;
int minWeight = -1;
void push(int weight) {
Node* newNode = (Node*)malloc(sizeof(Node));
newNode->weight = weight;
newNode->next = stack;
stack = newNode;
if (minWeight == -1 || weight < minWeight) {
minWeight = weight;
}
}
void pop() {
if (stack == NULL) {
return;
}
Node* top = stack;
stack = stack->next;
free(top);
if (stack == NULL) {
minWeight = -1;
}
}
int getMinWeight() {
return minWeight;
}
int main() {
char command[10];
int weight;
while (scanf("%s", command) != EOF) {
if (strcmp(command, "push") == 0) {
scanf("%d", &weight);
push(weight);
} else if (strcmp(command, "pop") == 0) {
pop();
} else if (strcmp(command, "min") == 0) {
int min = getMinWeight();
if (min != -1) {
printf("%d\n", min);
}
}
}
return 0;
}
这段代码使用堆栈(stack)数据结构来实现叠猪游戏。每个猪的重量被存储在一个链表节点(Node)中,而链表的头部代表猪堆的顶部。初始时,堆栈为空,最轻的猪的重量为-1。
程序逐行读取输入,根据命令执行相应的操作。当输入是"push n"时,程序将创建一个新的节点,并将其压入堆栈。如果新节点的重量小于当前最轻的猪的重量(或堆栈为空),则更新最轻猪的重量。当输入是"pop"时,程序将从堆栈中弹出一个节点(如果堆栈不为空)。如果堆栈为空,最轻猪的重量将被重置为-1。当输入是"min"时,程序将输出当前最轻的猪的重量(如果堆栈不为空)。
请注意,此代码假定输入是有效的,并且不会超出内存限制。你可以根据需要对其进行修改和扩展。
第4题:重建二叉树
给定一棵二叉树的前序遍历和中序遍历的结果,求其后序遍历。
时间限制:1000
内存限制:65536
输入
输入可能有多组,以EOF结束。 每组输入包含两个字符串,分别为树的前序遍历和中序遍历。每个字符串中只包含大写字母且互不重复。
输出
对于每组输入,用一行来输出它后序遍历结果。
样例输入
DBACEGF ABCDEFG
BCAD CBAD
样例输出
ACBFGED
CDAB
以下是使用C语言编写的解决方案:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct Node {
char value;
struct Node* left;
struct Node* right;
} Node;
Node* buildTree(char* preorder, char* inorder, int preStart, int preEnd, int inStart, int inEnd) {
if (preStart > preEnd || inStart > inEnd) {
return NULL;
}
char rootValue = preorder[preStart];
int rootIndex = 0;
for (int i = inStart; i <= inEnd; i++) {
if (inorder[i] == rootValue) {
rootIndex = i;
break;
}
}
int leftSize = rootIndex - inStart;
Node* root = (Node*)malloc(sizeof(Node));
root->value = rootValue;
root->left = buildTree(preorder, inorder, preStart + 1, preStart + leftSize, inStart, rootIndex - 1);
root->right = buildTree(preorder, inorder, preStart + leftSize + 1, preEnd, rootIndex + 1, inEnd);
return root;
}
void postorderTraversal(Node* root) {
if (root == NULL) {
return;
}
postorderTraversal(root->left);
postorderTraversal(root->right);
printf("%c", root->value);
}
int main() {
char preorder[100];
char inorder[100];
while (scanf("%s %s", preorder, inorder) != EOF) {
int preLength = strlen(preorder);
int inLength = strlen(inorder);
Node* root = buildTree(preorder, inorder, 0, preLength - 1, 0, inLength - 1);
postorderTraversal(root);
printf("\n");
free(root);
}
return 0;
}
这段代码实现了根据前序遍历和中序遍历结果重建二叉树,并输出后序遍历结果。
程序逐行读取输入的前序遍历和中序遍历结果,并调用buildTree
函数构建二叉树。buildTree
函数根据当前的前序遍历序列、中序遍历序列以及其在序列中的起始和结束位置进行递归构建。在每次递归中,找到当前根节点的值,然后通过在中序遍历序列中找到根节点的位置,将序列分为左子树和右子树。然后,递归地构建左子树和右子树,并将它们连接到当前根节点上。
构建完二叉树后,调用postorderTraversal
函数进行后序遍历,并输出结果。postorderTraversal
函数使用递归方式进行后序遍历,先遍历左子树,再遍历右子树,最后输出当前节点的值。
请注意,此代码假定输入是有效的,并且不会超出内存限制。你可以根据需要对其进行修改和扩展。