C/C++编程(1~8级)全部真题・点这里
第1题:走出迷宫
当你站在一个迷宫里的时候,往往会被错综复杂的道路弄得失去方向感,如果你能得到迷宫地图,事情就会变得非常简单。
假设你已经得到了一个n*m的迷宫的图纸,请你找出从起点到出口的最短路。
时间限制:1000
内存限制:65536
输入
第一行是两个整数n和m(1<=n,m<=100),表示迷宫的行数和列数。 接下来n行,每行一个长为m的字符串,表示整个迷宫的布局。字符’.‘表示空地,’#'表示墙,'S’表示起点,'T’表示出口。
输出
输出从起点到出口最少需要走的步数。
样例输入
3 3
S#T
.#.
…
样例输出
6
以下是一个使用C语言编写的解决方案:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_SIZE 100
typedef struct {
int x;
int y;
} Point;
typedef struct {
Point point;
int distance;
} QueueNode;
typedef struct {
QueueNode data[MAX_SIZE];
int front;
int rear;
} Queue;
void initQueue(Queue *queue) {
queue->front = 0;
queue->rear = 0;
}
int isQueueEmpty(Queue *queue) {
return queue->front == queue->rear;
}
int isQueueFull(Queue *queue) {
return (queue->rear + 1) % MAX_SIZE == queue->front;
}
void enqueue(Queue *queue, QueueNode node) {
if (isQueueFull(queue)) {
printf("Error: Queue is full.\n");
return;
}
queue->data[queue->rear] = node;
queue->rear = (queue->rear + 1) % MAX_SIZE;
}
QueueNode dequeue(Queue *queue) {
if (isQueueEmpty(queue)) {
printf("Error: Queue is empty.\n");
QueueNode emptyNode = {{-1, -1}, -1};
return emptyNode;
}
QueueNode node = queue->data[queue->front];
queue->front = (queue->front + 1) % MAX_SIZE;
return node;
}
int isValid(int x, int y, int n, int m) {
return x >= 0 && x < n && y >= 0 && y < m;
}
int shortestPath(char maze[][MAX_SIZE], int n, int m, Point start, Point end) {
int dx[] = {-1, 1, 0, 0};
int dy[] = {0, 0, -1, 1};
Queue queue;
initQueue(&queue);
int visited[MAX_SIZE][MAX_SIZE] = {0};
visited[start.x][start.y] = 1;
QueueNode startNode = {start, 0};
enqueue(&queue, startNode);
while (!isQueueEmpty(&queue)) {
QueueNode currentNode = dequeue(&queue);
Point currentPoint = currentNode.point;
int currentDistance = currentNode.distance;
if (currentPoint.x == end.x && currentPoint.y == end.y) {
return currentDistance;
}
for (int i = 0; i < 4; i++) {
int newX = currentPoint.x + dx[i];
int newY = currentPoint.y + dy[i];
if (isValid(newX, newY, n, m) && maze[newX][newY] != '#' && !visited[newX][newY]) {
visited[newX][newY] = 1;
Point newPoint = {newX, newY};
QueueNode newNode = {newPoint, currentDistance + 1};
enqueue(&queue, newNode);
}
}
}
return -1; // 没有找到路径
}
int main() {
int n, m;
scanf("%d %d", &n, &m);
char maze[MAX_SIZE][MAX_SIZE];
Point start, end;
for (int i = 0; i < n; i++) {
scanf("%s", maze[i]);
for (int j = 0; j < m; j++) {
if (maze[i][j] == 'S') {
start.x = i;
start.y = j;
} else if (maze[i][j] == 'T') {
end.x = i;
end.y = j;
}
}
}
int shortestDistance = shortestPath(maze, n, m, start, end);
printf("%d\n", shortestDistance);
return 0;
}
在给定的示例输入下,该程序将产生以下输出:
6
该程序使用广度优先搜索(BFS)算法来找到从起点到出口的最短路径。它使用一个队列来保存待处理的节点,并使用一个二维数组来记录已访问的位置。
程序首先读取迷宫的行数和列数,然后读取迷宫的布局。通过遍历迷宫,找到起点和出口的位置。
接下来,程序使用BFS算法来搜索最短路径。它从起点开始,将起点入队,并将起点标记为已访问。然后,它进入一个循环,直到队列为空。请注意,在使用这个解决方案时,输入的迷宫地图必须符合以下要求:
-
'S’表示起点,只能有一个。
-
'T’表示出口,只能有一个。
-
'#'表示墙。
-
'.'表示空地。
此外,该程序假设迷宫是连通的,即从起点到出口存在至少一条路径。如果迷宫是不连通的,或者不存在从起点到出口的路径,程序将返回-1。
第2题:拯救公主
多灾多难的公主又被大魔王抓走啦!国王派遣了第一勇士阿福去拯救她。
身为超级厉害的术士,同时也是阿福的好伙伴,你决定祝他一臂之力。你为阿福提供了一张大魔王根据地的地图,上面标记了阿福和公主所在的位置,以及一些不能够踏入的禁区。你还贴心地为阿福制造了一些传送门,通过一个传送门可以瞬间转移到任意一个传送门,当然阿福也可以选择不通过传送门瞬移。传送门的位置也被标记在了地图上。此外,你还查探到公主所在的地方被设下了结界,需要集齐K种宝石才能打开。当然,你在地图上也标记出了不同宝石所在的位置。
你希望阿福能够带着公主早日凯旋。于是在阿福出发之前,你还需要为阿福计算出他最快救出公主的时间。
地图用一个R×C的字符矩阵来表示。字符S表示阿福所在的位置,字符E表示公主所在的位置,字符#表示不能踏入的禁区,字符$表示传送门,字符.表示该位置安全,数字字符0至4表示了宝石的类型。阿福每次可以从当前的位置走到他上下左右四个方向上的任意一个位置,但不能走出地图边界。阿福每走一步需要花费1个单位时间,从一个传送门到达另一个传送门不需要花费时间。当阿福走到宝石所在的位置时,就视为得到了该宝石,不需要花费额外时间。
时间限制:1000
内存限制:65536
输入
第一行是一个正整数T(1 <= T <= 10),表示一共有T组数据。 每一组数据的第一行包含了三个用空格分开的正整数R、C(2 <= R, C <= 200)和K,表示地图是一个R×C的矩阵,而阿福需要集齐K种宝石才能够打开拘禁公主的结界。 接下来的R行描述了地图的具体内容,每一行包含了C个字符。字符含义如题目描述中所述。保证有且仅有一个S和E。$的数量不超过10个。宝石的类型在数字0至4范围内,即不会超过5种宝石。
输出
对于每一组数据,输出阿福救出公主所花费的最少单位时间。若阿福无法救出公主,则输出“oop!”(只输出引号里面的内容,不输出引号)。每组数据的输出结果占一行。
样例输入
1
7 8 2
…
…S…#0.
.##…1…
.0#…
…1#…
…##E…
…1…
样例输出
11
以下是一个使用C语言编写的解决方案:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_SIZE 200
#define INF 999999
typedef struct {
int x;
int y;
} Point;
typedef struct {
Point point;
int distance;
} QueueNode;
typedef struct {
QueueNode data[MAX_SIZE * MAX_SIZE];
int front;
int rear;
} Queue;
void initQueue(Queue *queue) {
queue->front = 0;
queue->rear = 0;
}
int isQueueEmpty(Queue *queue) {
return queue->front == queue->rear;
}
int isQueueFull(Queue *queue) {
return (queue->rear + 1) % (MAX_SIZE * MAX_SIZE) == queue->front;
}
void enqueue(Queue *queue, QueueNode node) {
if (isQueueFull(queue)) {
printf("Error: Queue is full.\n");
return;
}
queue->data[queue->rear] = node;
queue->rear = (queue->rear + 1) % (MAX_SIZE * MAX_SIZE);
}
QueueNode dequeue(Queue *queue) {
if (isQueueEmpty(queue)) {
printf("Error: Queue is empty.\n");
QueueNode emptyNode = {{-1, -1}, -1};
return emptyNode;
}
QueueNode node = queue->data[queue->front];
queue->front = (queue->front + 1) % (MAX_SIZE * MAX_SIZE);
return node;
}
int isValid(int x, int y, int r, int c) {
return x >= 0 && x < r && y >= 0 && y < c;
}
int shortestRescueTime(char map[][MAX_SIZE], int r, int c, int k, Point start, Point end) {
int dx[] = {-1, 1, 0, 0};
int dy[] = {0, 0, -1, 1};
Queue queue;
initQueue(&queue);
int visited[MAX_SIZE][MAX_SIZE][1 << 5] = {0};
visited[start.x][start.y][0] = 1;
QueueNode startNode = {start, 0};
enqueue(&queue, startNode);
while (!isQueueEmpty(&queue)) {
QueueNode currentNode = dequeue(&queue);
Point currentPoint = currentNode.point;
int currentDistance = currentNode.distance;
if (currentPoint.x == end.x && currentPoint.y == end.y) {
return currentDistance;
}
for (int i = 0; i < 4; i++) {
int newX = currentPoint.x + dx[i];
int newY = currentPoint.y + dy[i];
if (isValid(newX, newY, r, c) && map[newX][newY] != '#' && !visited[newX][newY][0]) {
int newMask = 0;
if (map[newX][newY] >= '0' && map[newX][newY] <= '4') {
int gemType = map[newX][newY] - '0';
newMask = (1 << gemType);
}
for (int j = 0; j < (1 << k); j++) {
int nextMask = j | newMask;
if (!visited[newX][newY][nextMask]) {
visited[newX][newY][nextMask] = 1;
Point newPoint = {newX, newY};
QueueNode newNode = {newPoint, currentDistance + 1};
enqueue(&queue, newNode);
}
}
}
}
}
return -1; // 无法救出公主
}
int main() {
int t;
scanf("%d", &t);
while (t--) {
int r, c, k;
scanf("%d %d %d", &r, &c, &k);
char map[MAX_SIZE][MAX_SIZE];
Point start, end;
for (int i = 0; i < r; i++) {
scanf("%s", map[i]);
for (int j = 0; j < c; j++) {
if (map[i][j] == 'S') {
start.x = i;
start.y = j;
} else if (map[i][j] == 'E') {
end.x = i;
end.y = j;
}
}
}
int shortestTime = shortestRescueTime(map, r, c, k, start, end);
if (shortestTime == -1) {
printf("oop!\n");
} else {
printf("%d\n", shortestTime);
}
}
return 0;
}
在此解决方案中,我们使用了广度优先搜索(BFS)来寻找阿福救出公主的最短时间。我们使用一个队列来存储待处理的节点,并使用一个三维数组来记录已经访问过的位置和已经获得的宝石类型。通过遍历四个方向上的相邻位置,我们检查是否可以移动到该位置,如果可以移动,则将该位置加入队列,并更新已访问数组和距离数组。如果我们找到了公主的位置,我们返回当前的距离,表示成功救出公主。如果队列为空而且我们仍然没有找到公主的位置,则表示无法救出公主,返回-1。
请注意,此解决方案假设输入的地图是合法的,并且可以找到一条路径来救出公主。如果地图不合法或者无法救出公主,则输出"oop!"。
第3题:有多少种二叉树
输入n(1<n<13),求n个结点的二叉树有多少种形态
时间限制:1000
内存限制:65536
输入
整数n
输出
答案
样例输入
3
样例输出
5
这是一个经典的动态规划问题,称为卡塔兰数(Catalan Number)。可以使用动态规划的方法来解决。
首先,我们可以观察到,对于一个二叉树来说,根节点的左子树和右子树的结点数量之和等于总结点数量减去1。因此,我们可以用一个递归的方式来计算二叉树的种类数量。
定义一个函数 countTrees(n)
,表示 n 个结点的二叉树的种类数量。对于每一个 i,我们可以将其作为根节点,然后左子树的结点数量为 i-1,右子树的结点数量为 n-i。因此,可以得到递归关系式:
countTrees(n) = countTrees(0) * countTrees(n-1) + countTrees(1) * countTrees(n-2) + ... + countTrees(n-1) * countTrees(0)
初始条件为 countTrees(0) = 1
,表示空树的一种形态。
下面是使用动态规划的 C 语言代码实现:
#include <stdio.h>
long long countTrees(int n) {
long long dp[n+1];
dp[0] = 1;
for (int i = 1; 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 result = countTrees(n);
printf("%lld\n", result);
return 0;
}
在这个解决方案中,我们使用一个数组 dp
来存储计算过的结果,避免重复计算。我们使用两层循环,外层循环遍历结点数量,内层循环计算每个结点数量对应的二叉树种类数量。最后,输出 dp[n]
即为结果。
请注意,由于结果可能非常大,我们使用了 long long
类型来保存结果。
第4题: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
这是一个简单的问题,可以使用优先队列(堆)来解决。我们可以遍历每个序列,将序列中的数字依次加入优先队列,保持队列的大小为 n。这样,优先队列中的元素就是最小的 n 个数。
下面是使用 C 语言编写的解决方案:
#include <stdio.h>
#include <stdlib.h>
#define MAX_SIZE 2000
typedef struct {
int value;
int sequenceIndex;
int numberIndex;
} Number;
typedef struct {
Number *data;
int size;
int capacity;
} MinHeap;
MinHeap* createMinHeap(int capacity) {
MinHeap *heap = (MinHeap*) malloc(sizeof(MinHeap));
heap->data = (Number*) malloc(sizeof(Number) * capacity);
heap->size = 0;
heap->capacity = capacity;
return heap;
}
void destroyMinHeap(MinHeap *heap) {
free(heap->data);
free(heap);
}
void swap(Number *a, Number *b) {
Number temp = *a;
*a = *b;
*b = temp;
}
void heapifyUp(MinHeap *heap, int index) {
while (index > 0) {
int parentIndex = (index - 1) / 2;
if (heap->data[index].value < heap->data[parentIndex].value) {
swap(&heap->data[index], &heap->data[parentIndex]);
index = parentIndex;
} else {
break;
}
}
}
void heapifyDown(MinHeap *heap, int index) {
while (index < heap->size) {
int leftChildIndex = 2 * index + 1;
int rightChildIndex = 2 * index + 2;
int smallestIndex = index;
if (leftChildIndex < heap->size && heap->data[leftChildIndex].value < heap->data[smallestIndex].value) {
smallestIndex = leftChildIndex;
}
if (rightChildIndex < heap->size && heap->data[rightChildIndex].value < heap->data[smallestIndex].value) {
smallestIndex = rightChildIndex;
}
if (smallestIndex != index) {
swap(&heap->data[index], &heap->data[smallestIndex]);
index = smallestIndex;
} else {
break;
}
}
}
void insertNumber(MinHeap *heap, int value, int sequenceIndex, int numberIndex) {
if (heap->size == heap->capacity) {
if (value >= heap->data[0].value) {
return;
}
heap->data[0].value = value;
heap->data[0].sequenceIndex = sequenceIndex;
heap->data[0].numberIndex = numberIndex;
heapifyDown(heap, 0);
} else {
heap->data[heap->size].value = value;
heap->data[heap->size].sequenceIndex = sequenceIndex;
heap->data[heap->size].numberIndex = numberIndex;
heapifyUp(heap, heap->size);
heap->size++;
}
}
void findSmallestSums(int m, int n, int sequences[][MAX_SIZE]) {
MinHeap *heap = createMinHeap(n);
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
insertNumber(heap, sequences[i][j], i, j);
}
}
for (int i = 0; i < n; i++) {
printf("%d ", heap->data[i].value);
}
printf("\n");
destroyMinHeap(heap);
}
int main() {
int t;
scanf("%d", &t);
while (t--) {
int m, n;
scanf("%d %d", &m, &n);
int sequences[100][MAX_SIZE];
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
scanf("%d", &sequences[i][j]);
}
}
findSmallestSums(m, n, sequences);
}
return 0;
}