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

2023年05月 C/C++(七级)真题解析#中国电子学会#全国青少年软件编程等级考试_第1张图片

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

第1题:城堡问题

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

以下是一个用C语言编写的解决方案,实现了计算城堡的房间数和最大房间大小的功能:

#include 

#define MAX_M 50
#define MAX_N 50

int castle[MAX_M][MAX_N]; // 城堡地图
int visited[MAX_M][MAX_N]; // 记录方块是否被访问过
int roomSize[MAX_M * MAX_N]; // 每个房间的大小
int maxRoomSize = 0; // 最大房间的大小
int roomCount = 0; // 房间数

// 方块的四个方向
const int WEST = 1;
const int NORTH = 2;
const int EAST = 4;
const int SOUTH = 8;

// 方块的坐标增量
const int dx[4] = {-1, 0, 1, 0};
const int dy[4] = {0, -1, 0, 1};

// 深度优先搜索遍历房间
void dfs(int x, int y) {
    visited[x][y] = 1; // 标记为已访问
    roomSize[roomCount]++; // 当前房间大小加一
    maxRoomSize = (roomSize[roomCount] > maxRoomSize) ? roomSize[roomCount] : maxRoomSize;

    // 遍历四个方向
    for (int i = 0; i < 4; i++) {
        // 判断当前方向是否有墙
        if (!(castle[x][y] & (1 << i))) {
            int nx = x + dx[i];
            int ny = y + dy[i];

            // 判断下一个方块是否合法且未访问过
            if (nx >= 0 && nx < MAX_M && ny >= 0 && ny < MAX_N && !visited[nx][ny]) {
                dfs(nx, ny);
            }
        }
    }
}

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]);
        }
    }

    // 遍历每个方块
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++) {
            if (!visited[i][j]) {
                roomCount++;
                dfs(i, j);
            }
        }
    }

    printf("%d\n%d\n", roomCount, maxRoomSize);

    return 0;
}

这个程序首先定义了一些常量和全局变量,包括城堡地图、方块访问状态、每个房间的大小、最大房间的大小和房间数等。

然后,程序通过深度优先搜索遍历每个房间。对于每个未访问过的方块,将其作为起点进行深度优先搜索。在搜索过程中,将已访问过的方块标记为已访问,同时统计当前房间的大小,并更新最大房间的大小。搜索完成后,房间数加一。

最后,程序输出房间数和最大房间的大小。

第2题: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语言解决方案,使用优先队列(Priority Queue)实现了按照定义的优先级规则添加和删除元素,并输出优先级最高和最低的元素。

#include 
#include 
#include 
#include 

#define MAX_SIZE 10

// 结点定义
typedef struct {
    int value; // 元素的值
    int prime_factors; // 质因数的数量
} Node;

// 优先队列定义
typedef struct {
    Node* heap; // 使用数组表示堆
    int size; // 当前堆的大小
    int max_size; // 堆的最大容量
} PriorityQueue;

// 创建一个新的结点
Node* createNode(int value) {
    Node* newNode = (Node*)malloc(sizeof(Node));
    newNode->value = value;
    newNode->prime_factors = 0;
    return newNode;
}

// 交换两个结点
void swap(Node* a, Node* b) {
    Node temp = *a;
    *a = *b;
    *b = temp;
}

// 判断一个数是否为质数
bool isPrime(int n) {
    if (n <= 1) {
        return false;
    }

    int sqrt_n = sqrt(n);
    for (int i = 2; i <= sqrt_n; i++) {
        if (n % i == 0) {
            return false;
        }
    }
    return true;
}

// 计算一个数的质因数数量
int countPrimeFactors(int n) {
    int count = 0;
    for (int i = 2; i <= n; i++) {
        if (n % i == 0 && isPrime(i)) {
            count++;
        }
    }
    return count;
}

// 初始化优先队列
PriorityQueue* createPriorityQueue(int max_size) {
    PriorityQueue* pq = (PriorityQueue*)malloc(sizeof(PriorityQueue));
    pq->heap = (Node*)malloc(max_size * sizeof(Node));
    pq->size = 0;
    pq->max_size = max_size;
    return pq;
}

// 插入元素到优先队列
void insert(PriorityQueue* pq, Node* node) {
    // 如果队列已满,先删除优先级最低的元素
    if (pq->size == pq->max_size) {
        int min_index = 0;
        for (int i = 1; i < pq->max_size; i++) {
            if (pq->heap[i].prime_factors < pq->heap[min_index].prime_factors) {
                min_index = i;
            } else if (pq->heap[i].prime_factors == pq->heap[min_index].prime_factors &&
                       pq->heap[i].value > pq->heap[min_index].value) {
                min_index = i;
            }
        }
        // 删除优先级最低的元素
        free(pq->heap[min_index]);
        pq->heap[min_index] = node;
    } else {
        pq->heap[pq->size++] = *node;
    }

    // 对堆进行自下而上的调整
    int index = pq->size - 1;
    while (index > 0) {
        int parent = (index - 1) / 2;
        if (pq->heap[index].prime_factors < pq->heap[parent].prime_factors) {
            break;
        } else if (pq->heap[index].prime_factors == pq->heap[parent].prime_factors &&
                   pq->heap[index].value <= pq->heap[parent].value) {
            break;
        }
        swap(&pq->heap[index], &pq->heap[parent]);
        index = parent;
    }
}

// 删除优先队列中的优先级最高元素,并返回其值
int deleteMax(PriorityQueue* pq) {
    if (pq->size == 0) {
        return -1; // 队列为空
    }

    int max_value = pq->heap[0].value;
    free(pq->heap[0]);
    pq->heap[0] = pq->heap[pq->size - 1];
    pq->size--;

    // 对堆进行自上而下的调整
    int index = 0;
    while (true) {
        int left_child = 2 * index + 1;
        int right_child = 2 * index + 2;
        int max_child = index;

        if (left_child < pq->size &&
            (pq->heap[left_child].prime_factors > pq->heap[max_child].primefactors ||
             (pq->heap[left_child].prime_factors == pq->heap[max_child].prime_factors &&
              pq->heap[left_child].value > pq->heap[max_child].value))) {
            max_child = left_child;
        }
        if (right_child < pq->size &&
            (pq->heap[right_child].prime_factors > pq->heap[max_child].prime_factors ||
             (pq->heap[right_child].prime_factors == pq->heap[max_child].prime_factors &&
              pq->heap[right_child].value > pq->heap[max_child].value))) {
            max_child = right_child;
        }

        if (max_child == index) {
            break;
        }

        swap(&pq->heap[index], &pq->heap[max_child]);
        index = max_child;
    }

    return max_value;
}

int main() {
    int num;
    scanf("%d", &num);

    PriorityQueue* pq = createPriorityQueue(MAX_SIZE);

    for (int i = 0; i < num; i++) {
        for (int j = 0; j < MAX_SIZE; j++) {
            int n;
            scanf("%d", &n);

            Node* newNode = createNode(n);
            newNode->prime_factors = countPrimeFactors(n);

            insert(pq, newNode);
        }

        int max_value = deleteMax(pq);
        int min_value = deleteMax(pq);

        printf("%d %d\n", max_value, min_value);
    }

    return 0;
}

注意:由于输入数据量较大,为了避免超时,可以适当增大堆的最大容量(MAX_SIZE)和质因数计算的上限(10000000)。

第3题:二叉树的深度

给定一棵二叉树,求该二叉树的深度
二叉树深度定义:从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的节点个数为树的深度
时间限制:1000
内存限制:65535
输入
第一行是一个整数n,表示二叉树的结点个数。二叉树结点编号从1到n,根结点为1,n <= 10 接下来有n行,依次对应二叉树的n个节点。 每行有两个整数,分别表示该节点的左儿子和右儿子的节点编号。如果第一个(第二个)数为-1则表示没有左(右)儿子
输出
输出一个整型数,表示树的深度
样例输入
3
2 3
-1 -1
-1 -1
样例输出
2

以下是一个求二叉树深度的C语言解决方案,使用递归的方式遍历二叉树并计算深度:

#include 
#include 

// 二叉树节点定义
typedef struct TreeNode {
    int val;
    struct TreeNode* left;
    struct TreeNode* right;
} TreeNode;

// 创建一个新的二叉树节点
TreeNode* createNode(int val) {
    TreeNode* newNode = (TreeNode*)malloc(sizeof(TreeNode));
    newNode->val = val;
    newNode->left = NULL;
    newNode->right = NULL;
    return newNode;
}

// 递归计算二叉树的深度
int maxDepth(TreeNode* root) {
    if (root == NULL) {
        return 0;
    } else {
        int leftDepth = maxDepth(root->left);
        int rightDepth = maxDepth(root->right);
        return 1 + (leftDepth > rightDepth ? leftDepth : rightDepth);
    }
}

// 构建二叉树
TreeNode* buildTree(int n) {
    TreeNode** nodes = (TreeNode**)malloc((n + 1) * sizeof(TreeNode*));
    for (int i = 0; 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];
        }
    }

    TreeNode* root = nodes[1];
    free(nodes);
    return root;
}

int main() {
    int n;
    scanf("%d", &n);

    TreeNode* root = buildTree(n);
    int depth = maxDepth(root);
    printf("%d\n", depth);

    return 0;
}

注意:根据题目描述,二叉树的节点编号从1到n,其中根节点为1。输入时按照节点编号的顺序给出节点的左儿子和右儿子的编号,如果没有左(右)儿子,则用-1表示。在构建二叉树时,我们使用了一个辅助数组nodes来保存每个节点的指针,便于后续的连接操作。最后,我们调用maxDepth函数计算二叉树的深度,并输出结果。

第4题:快速堆猪

小明有很多猪,他喜欢玩叠猪游戏,就是将猪一头头叠起来。猪叠上去后,还可以把顶上的猪拿下来。小明知道每头猪的重量,而且他还随时想知道叠在那里的猪最轻的是多少斤。
时间限制: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 
#include 
#include 

#define MAX_PIGS 20000

typedef struct {
    int weight;
    bool is_valid;
} Pig;

Pig pigs[MAX_PIGS];
int top;

void push(int weight) {
    pigs[top].weight = weight;
    pigs[top].is_valid = true;
    top++;
}

void pop() {
    if (top > 0) {
        top--;
        pigs[top].is_valid = false;
    }
}

int min() {
    int min_weight = -1;
    for (int i = 0; i < top; i++) {
        if (pigs[i].is_valid) {
            if (min_weight == -1 || pigs[i].weight < min_weight) {
                min_weight = pigs[i].weight;
            }
        }
    }
    return min_weight;
}

int main() {
    char command[10];

    top = 0;

    int n;
    scanf("%d", &n);

    for (int i = 0; i < n; i++) {
        scanf("%s", command);
        if (strcmp(command, "push") == 0) {
            int weight;
            scanf("%d", &weight);
            push(weight);
        } else if (strcmp(command, "pop") == 0) {
            pop();
        } else if (strcmp(command, "min") == 0) {
            int min_weight = min();
            if (min_weight != -1) {
                printf("%d\n", min_weight);
            }
        }
    }

    return 0;
}

在这个解决方案中,我们使用了一个结构体数组pigs来表示堆猪,每个元素包含猪的重量和是否有效的标志。变量top表示堆顶的索引。

我们定义了三个函数:

  • push函数用于将一头重量为weight的猪叠到堆中,将其重量和有效标志保存在pigs数组中,并更新top

  • pop函数用于将堆顶的猪赶走,即将其有效标志设为false,并更新top

  • min函数用于计算堆中最轻的猪的重量,遍历pigs数组并找到有效猪中的最小重量。

main函数中,我们读取输入的指令并根据指令调用相应的函数。如果是push指令,我们读取猪的重量并调用push函数;如果是pop指令,我们调用pop函数;如果是min指令,我们调用min函数并输出最轻猪的重量(如果有猪的话)。

请注意,我们假设输入的指令合法且不会导致堆栈溢出。

你可能感兴趣的:(c语言,c++,算法,等级考试,电子学会)