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

在这里插入图片描述

第1题:最佳路径

如下所示的由正整数数字构成的三角形:
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
从三角形的顶部到底部有很多条不同的路径。对于每条路径,把路径上面的数加起来可以得到一个和,和最大的路径称为最佳路径。你的任务就是求出最佳路径上的数字之和。
注意:路径上的每一步只能从一个数走到下一层上和它最近的下边(正下方)的数或者右边(右下方)的数。
时间限制:1000
内存限制:65536
输入
第一行为三角形高度100>=h>=1,同时也是最底层边的数字的数目。 从第二行开始,每行为三角形相应行的数字,中间用空格分隔。
输出
最佳路径的长度数值。
样例输入
5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
样例输出
30

以下是解决该问题的C语言代码实现:

#include <stdio.h>

int maxPathSum(int triangle[][100], int N) {
    
    
    int dp[100][100] = {
    
    0};

    // 初始化最底层的dp值为三角形最底层的值
    for (int i = 0; i < N; i++) {
    
    
        dp[N - 1][i] = triangle[N - 1][i];
    }

    // 从倒数第二层开始迭代计算dp值
    for (int i = N - 2; i >= 0; i--) {
    
    
        for (int j = 0; j <= i; j++) {
    
    
            dp[i][j] = triangle[i][j] + (dp[i + 1][j] > dp[i + 1][j + 1] ? dp[i + 1][j] : dp[i + 1][j + 1]);
        }
    }

    return dp[0][0];
}

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

    int triangle[100][100];
    for (int i = 0; i < N; i++) {
    
    
        for (int j = 0; j <= i; j++) {
    
    
            scanf("%d", &triangle[i][j]);
        }
    }

    int maxSum = maxPathSum(triangle, N);
    printf("%d\n", maxSum);

    return 0;
}

该代码使用动态规划的思想来解决问题。定义一个dp数组,其中dp[i][j]表示从三角形顶部到达位置(i, j)的最佳路径的数字之和。

通过迭代计算dp数组,同时返回dp[0][0]作为结果。

首先,将dp数组的最底层初始化为三角形最底层的值,即dp[N-1][i] = triangle[N-1][i]。

然后,从倒数第二层开始迭代计算dp数组。对于位置(i, j),dp[i][j]的值可以通过以下方式计算:

  • dp[i][j] = triangle[i][j] + max(dp[i+1][j], dp[i+1][j+1]),即当前位置的值加上下一层相邻位置的最佳路径的数字之和。

最后,返回dp[0][0]作为结果,即最佳路径的数字之和。

第2题:数字构造

火山宝打算造一个 n 位的十进制数字出来。
对于 1 到 n 中的每一个 i,火山宝可以从 xi,1, …, xi,ki 这 ki 个 0-9 的数字中选择一个作为 ai。
在选择结束后,a1a2…an 形成了一个 n 位的十进制数——这就是火山宝造出来的数。
你需要帮火山宝计算他能造出的数中,有多少个是 3 的倍数。
时间限制:1000
内存限制:65536
输入
第一行输入一个整数 n(1 ≤ n ≤ 18),表示数字的位数。 接下来 n 行,每行第一个整数 ki (1 ≤ ki ≤ 10),表示第 i 中候选的数字数量。接着是 ki 个两两不同的 0-9 范围内的数字 xi,1, …, xi,ki。 输入保证 0 不是第一位的可选项。
输出
你需要输出一行一个整数,表示火山宝能造出的数字中,3 的倍数的数量。
样例输入
样例输入1:
2
5 5 6 7 8 9
5 0 1 2 3 4
样例输入2:
5
9 1 2 3 4 5 6 7 8 9
10 0 1 2 3 4 5 6 7 8 9
10 0 1 2 3 4 5 6 7 8 9
10 0 1 2 3 4 5 6 7 8 9
10 0 1 2 3 4 5 6 7 8 9
样例输出
样例输出1:
9
样例输出2:
30000
提示
样例1能造出来的 3 的倍数有 51, 54,60,63,72,81,84,90, 93。

要解决这个问题,可以使用回溯法来生成所有可能的数字,并检查每个数字是否是3的倍数。

以下是使用C语言实现的代码:

#include <stdio.h>
#include <stdbool.h>

int count = 0;

bool isMultipleOfThree(int num) {
    
    
    return num % 3 == 0;
}

void generateNumbers(int digits, int candidates[][10], int currentDigit, int currentNumber) {
    
    
    if (currentDigit > digits) {
    
    
        if (isMultipleOfThree(currentNumber)) {
    
    
            count++;
        }
        return;
    }

    for (int i = 0; i < candidates[currentDigit][0]; i++) {
    
    
        generateNumbers(digits, candidates, currentDigit + 1, currentNumber * 10 + candidates[currentDigit][i + 1]);
    }
}

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

    int candidates[18][10];
    for (int i = 1; i <= n; i++) {
    
    
        scanf("%d", &candidates[i][0]);
        for (int j = 1; j <= candidates[i][0]; j++) {
    
    
            scanf("%d", &candidates[i][j]);
        }
    }

    generateNumbers(n, candidates, 1, 0);

    printf("%d\n", count);

    return 0;
}

该代码通过递归的方式生成所有可能的数字。对于每一位,根据候选数字的数量进行循环,并将当前位的数字与之前的数字构成一个新的数。

在递归的过程中,如果生成的数字位数超过了给定的位数,则检查该数字是否是3的倍数。如果是,计数器count加1。

最后,输出计数器count的值,即火山宝能造出的数字中3的倍数的数量。

第3题:奶牛散步

从一个无限大的矩阵的中心点出发,一步只能向右走、向上走或向左走。恰好走N步且不经过已走的点共有多少种走法?
输入
一个数字,代表N,N<=1000
输出
输出有多少方案数模12345

样例输入
2
样例输出
7

要解决这个问题,可以使用动态规划的方法来计算不同步数下的方案数。

以下是使用C语言实现的代码:

#include <stdio.h>

int countWalks(int N) {
    
    
    int dp[2][3] = {
    
    0}; // 使用滚动数组保存状态

    dp[1][1] = 1; // 初始位置

    for (int step = 1; step <= N; step++) {
    
    
        int curr = step % 2; // 当前行的索引
        int prev = (step - 1) % 2; // 上一行的索引

        dp[curr][0] = (dp[prev][1] + dp[prev][2]) % 12345; // 向右走
        dp[curr][1] = (dp[prev][0] + dp[prev][2]) % 12345; // 向上走
        dp[curr][2] = (dp[prev][0] + dp[prev][1] + dp[prev][2]) % 12345; // 向左走
    }

    return dp[N % 2][0] + dp[N % 2][1] + dp[N % 2][2];
}

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

    int numWalks = countWalks(N);
    printf("%d\n", numWalks);

    return 0;
}

该代码使用滚动数组来保存状态,使用dp[i][j]表示走i步到达位置j的方案数。

初始时,将dp[1][1]设置为1,表示初始位置。

然后,从第2步开始迭代计算dp数组。对于每一步,根据上一步的方案数计算当前步的方案数:

  • 向右走:dp[curr][0] = (dp[prev][1] + dp[prev][2]) % 12345

  • 向上走:dp[curr][1] = (dp[prev][0] + dp[prev][2]) % 12345

  • 向左走:dp[curr][2] = (dp[prev][0] + dp[prev][1] + dp[prev][2]) % 12345

最后,返回dp[N % 2][0] + dp[N % 2][1] + dp[N % 2][2]作为结果,即走N步的方案数。

希望以上代码能帮助你解决问题!

第4题:吃奶酪

Jerry准备偷吃Tom的奶酪。所有的奶酪排成了一条直线,每块奶酪都有不同的美味程度。然而,如果有相邻两块奶酪都被Jerry偷吃,Tom就会发现这一点并迅速抓住Jerry。Jerry当然希望在不被Tom发现的条件下吃到的奶酪美味度总和最大。当然,他也可以选择一块奶酪都不吃。请你帮助他规划一下偷吃的方案,告诉他最多能偷吃到多少的美味度吧。
时间限制:1000
内存限制:65536
输入
第一行一个整数T (T<=100),表示测试数据组数。 接下来,每组测试数据包含两行。其中,第一行一个整数n (1 <= n <= 100,000) ,表示奶酪的数量;第二行n个整数,表示这一排直线上奶酪的美味程度,请注意,美味度保证能够被int类型存储,且可能是负数。
输出
对于每组测试数据,输出一个整数,表示Jerry可以吃到的最大美味度总和。请注意,美味度总和可能超过int存储范围
样例输入
2
4
1 2 3 1
5
2 7 9 3 1
样例输出
4
12

要解决这个问题,可以使用动态规划的方法来计算最大美味度总和。

以下是使用C语言实现的代码:

#include <stdio.h>

int max(int a, int b) {
    
    
    return (a > b) ? a : b;
}

long long int maxCheese(int n, int cheese[]) {
    
    
    long long int dp[100001] = {
    
    0};

    dp[0] = cheese[0];
    dp[1] = max(cheese[0], cheese[1]);

    for (int i = 2; i < n; i++) {
    
    
        dp[i] = max(dp[i - 1], dp[i - 2] + cheese[i]);
    }

    return dp[n - 1];
}

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

    while (T--) {
    
    
        int n;
        scanf("%d", &n);

        int cheese[100000];
        for (int i = 0; i < n; i++) {
    
    
            scanf("%d", &cheese[i]);
        }

        long long int maxSum = maxCheese(n, cheese);
        printf("%lld\n", maxSum);
    }

    return 0;
}

该代码使用动态规划来计算最大美味度总和。使用dp数组保存到达每个奶酪位置时的最大美味度总和。

初始时,dp[0]等于第一块奶酪的美味度,dp[1]等于第一块和第二块奶酪中较大的美味度。

然后,从第三块奶酪开始迭代计算dp数组。对于每个位置i,可以选择不偷第i块奶酪(保持dp[i-1]不变)或偷第i块奶酪(dp[i] = dp[i-2] + cheese[i])中较大的美味度总和。

最后,返回dp[n-1]作为结果,即Jerry可以吃到的最大美味度总和。

希望以上代码能帮助你解决问题!

猜你喜欢

转载自blog.csdn.net/gozhuyinglong/article/details/132381968