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

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

第1题:课程冲突

小 A 修了 n 门课程, 第 i 门课程是从第 ai 天一直上到第 bi 天。
定义两门课程的冲突程度为 : 有几天是这两门课程都要上的。
例如 a1=1,b1=3,a2=2,b2=4 时, 这两门课的冲突程度为 2。
现在你需要求的是这 n 门课中冲突程度最大的两门课的冲突程度。
时间限制:1000
内存限制:65536
输入
第一行一个正整数 n 表示课程数量。接下来 n 行,每行两个正整数 ai,bi。 2 ≤ n≤ 1000, 1 ≤ai ≤bi ≤ 1000。
输出
输出一个整数表示最大的冲突程度。
样例输入
3
1 3
2 4
5 5
样例输出
2

题目要求找出n门课程中冲突程度最大的两门课的冲突程度。冲突程度表示有几天是这两门课程都要上的。

解题思路:

(1)创建一个长度为1001的数组conflict,用于记录每一天有几门课程要上。

(2)遍历每一门课程,对于每门课程的时间范围[a, b],将conflict[a]~conflict[b]的值都加1,表示这些天有一门课程要上。

(3)遍历conflict数组,找到冲突程度最大的值,即为最大的冲突程度。

下面是使用C语言编写的解题代码:

#include 

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

    int conflict[1001] = {0};  // 记录每一天的冲突程度

    int i;
    for (i = 0; i < n; i++) {
        int a, b;
        scanf("%d %d", &a, &b);

        int j;
        for (j = a; j <= b; j++) {
            conflict[j]++;
        }
    }

    int maxConflict = 0;
    for (i = 1; i <= 1000; i++) {
        if (conflict[i] > maxConflict) {
            maxConflict = conflict[i];
        }
    }

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

    return 0;
}

在上述代码中,我们首先创建一个长度为1001的数组 conflict,用于记录每一天的冲突程度。初始时,数组中所有元素都为0。

然后,我们使用一个循环遍历每一门课程。对于每门课程的时间范围 [a, b],我们将 conflict[a]conflict[b] 的值都加1,表示这些天有一门课程要上。

接下来,我们再次遍历 conflict 数组,找到冲突程度最大的值,即为最大的冲突程度。

最后,我们将结果输出。

编译并运行上述代码,即可得到最大的冲突程度。

第2题:42点

42是:
· 组合数学上的第5个卡特兰数
· 字符’*‘的ASCII码
· 钼的原子序数
· 6与9的乘积结果的13进制表示
· 生命、宇宙以及任何事情的终极答案
· 以及……表达式(1+5)/2*(6-4)*7的值
因此,小机器人Marvin发明了这个叫42点的小游戏。在这个游戏中,玩家会获得n个数。玩家需要使用’+‘、’-‘、’*‘、’/‘、’(‘、’)'以及这n个数构成一个合法的中缀表达式,并使得该表达式的值为42。n个数之间的顺序可以改变。表达式运算过程中只能出现整数。
由于过于抑郁,Marvin无力完成这个游戏,于是来找你帮忙。你的任务是对于给定的n个数,判断他们是否能根据上述游戏规则算出42。
时间限制:1000
内存限制:65536
输入
第一行为一个数n,1<=n<=6。 第二行为n个数,每个数均为[1,13]范围内的整数
输出
输出一行,若可以算出42则输出“YES”,否则输出“NO”(注意大小写)
样例输入
6
1 5 2 6 4 7
样例输出
YES

为了解决这个问题,我们可以使用回溯法来尝试所有可能的表达式组合。下面是使用C语言编写的解题代码:

#include 
#include 

bool canGet42(int nums[], int count, int sum) {
    if (count == 0) {
        if (sum == 42) {
            return true;  // 当前表达式的结果等于42
        } else {
            return false;  // 当前表达式的结果不等于42
        }
    }

    // 尝试将当前数字加入表达式并递归调用
    if (canGet42(nums + 1, count - 1, sum + nums[0])) {
        return true;
    }

    // 尝试将当前数字减去表达式并递归调用
    if (canGet42(nums + 1, count - 1, sum - nums[0])) {
        return true;
    }

    // 尝试将当前数字乘以表达式并递归调用
    if (canGet42(nums + 1, count - 1, sum * nums[0])) {
        return true;
    }

    // 如果当前数字不为0且能整除表达式,则尝试将当前数字除以表达式并递归调用
    if (nums[0] != 0 && sum % nums[0] == 0 && canGet42(nums + 1, count - 1, sum / nums[0])) {
        return true;
    }

    return false;  // 无法得到42
}

bool canGet42Wrapper(int nums[], int count) {
    int sum = 0;
    return canGet42(nums, count, sum);
}

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

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

    if (canGet42Wrapper(nums, n)) {
        printf("YES\n");  // 可以得到42
    } else {
        printf("NO\n");  // 无法得到42
    }

    return 0;
}

在上述代码中,我们定义了 canGet42 函数来实现回溯法。函数中,我们首先检查剩余可用的数字个数是否为0,如果是,则检查当前表达式的结果是否等于42。如果是,返回 true;否则,返回 false

然后,我们使用递归调用来尝试将当前数字加入、减去、乘以、除以表达式,并对剩余数字进行递归调用。在递归调用之前,我们将当前数字与表达式的结果进行相应的运算,并将剩余数字列表和数字个数进行更新。在递归调用之后,我们返回递归调用的结果。

main 函数中,我们首先读取输入的数字个数和数字列表。然后,我们调用 canGet42Wrapper 函数来判断是否可以得到42。如果可以,输出 “YES”;否则,输出 “NO”。

编译并运行上述的代码可以解决该问题。你可以使用 C 语言编译器将代码保存为 .c 文件,然后编译并运行该文件来获取结果。

请注意,该代码使用了递归,可能在数字个数较大时会导致栈溢出。由于题目中给定的数字个数最多为 6,这不会成为问题。但如果需要处理更多的数字,可能需要使用其他方法,如动态规划。

第3题:最长下坡

小明天天沿着未名湖环湖路跑,有时候也觉得蛮累。
累的时候跑下坡就很开心。小明想知道最长的一段下坡有多长。
环湖路是个圆形,周长n米。每隔一米测一下路面高度,两个测高点之间的高度是单调变化或不变的。
问最长的一段下坡有多少米长。小明只能顺时针跑。下坡必须高度单调减少。
时间限制:1000
内存限制:65536
输入
第一行是整数n,表示环湖路一共n米长(2<=n<=100)。 第二行是n个整数,每个整数范围[0,10000],按顺时针顺序给出了n个测高点的高度。
输出
最长下坡路段的长度。
样例输入
样例输入1:
5
2 1 5 6 3
样例输入2:
5
2 1 5 4 3
样例输入3:
4
1 1 1 1
样例输出
样例输出1:
3
样例输出2:
4
样例输出3:
0
提示
这是个简单枚举题,枚举起点即可

为了解决这个问题,我们可以使用枚举的方法来找到最长的下坡路段。

我们可以从每个点开始枚举,然后向右遍历环湖路,找到下坡的最大长度。为了方便处理环形结构,我们可以将环湖路的数组复制一份拼接在原数组的后面,以便在遍历时能够正确处理环路。

下面是使用 C 语言编写的解题代码:

#include 

int findLongestDownhill(int heights[], int n) {
    int maxDownhill = 0;  // 最长下坡长度
    int currentDownhill = 0;  // 当前下坡长度

    // 复制数组并拼接在原数组后面
    int extendedHeights[200];
    for (int i = 0; i < n; i++) {
        extendedHeights[i] = heights[i];
        extendedHeights[i + n] = heights[i];
    }

    // 枚举起点
    for (int i = 0; i < n; i++) {
        currentDownhill = 0;
        int j = i;

        // 向右遍历
        while (extendedHeights[j] > extendedHeights[j + 1]) {
            currentDownhill++;
            j++;

            // 更新最长下坡长度
            if (currentDownhill > maxDownhill) {
                maxDownhill = currentDownhill;
            }
        }
    }

    return maxDownhill;
}

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

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

    int longestDownhill = findLongestDownhill(heights, n);
    printf("%d\n", longestDownhill);

    return 0;
}

在上述代码中,我们定义了 findLongestDownhill 函数来寻找最长的下坡路段。函数中,我们首先创建一个扩展的高度数组 extendedHeights,将原高度数组复制一份并拼接在后面,以便在遍历时能够正确处理环路。

然后,我们使用两个循环嵌套来枚举起点和向右遍历。在遍历过程中,我们使用 currentDownhill 变量来记录当前下坡长度,并使用 maxDownhill 变量来记录最长下坡长度。如果当前下坡长度大于最长下坡长度,则更新最长下坡长度。

main 函数中,我们首先读取输入的环湖路长度和高度数组。然后,我们调用 findLongestDownhill 函数来找到最长的下坡路段,并将结果输出。

编译并运行上述的代码可以解决该问题。你可以使用 C 语言编译器将代码保存为 .c 文件,然后编译并运行该文件来获取结果。

第4题:吃糖果

现有n(20 > n > 0)个糖果,每天可以吃1个,也可以每天吃2个,也可以每天吃3个,请计算共有多少种不同的吃法。
时间限制:1000
内存限制:65536
输入
输入的每一行包括一组测试数据,即为糖果数n。最后一行为0,表示测试结束。
输出
每一行输出对应一行输入的结果,即为吃法的数目。
样例输入
1
2
3
4
0
样例输出
1
2
4
7

这个问题可以通过动态规划来解决。我们定义一个数组 dp,其中 dp[i] 表示有 i 个糖果时的吃法总数。

根据题目要求,每天可以吃 1 个、2 个或 3 个糖果。因此,对于 dp[i],可以从 dp[i-1]dp[i-2]dp[i-3] 中转移得到。具体转移方式如下:

dp[i] = dp[i-1] + dp[i-2] + dp[i-3]

初始条件为 dp[0] = 1dp[1] = 1dp[2] = 2,因为当没有糖果时只有一种吃法,当有一个糖果时也只有一种吃法,当有两个糖果时有两种吃法(可以吃一个糖果两次或者吃两个糖果一次)。

下面是使用 C 语言编写的解题代码:

#include 

int countEatWays(int n) {
    int dp[21];
    dp[0] = 1;
    dp[1] = 1;
    dp[2] = 2;

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

    return dp[n];
}

int main() {
    int n;

    while (1) {
        scanf("%d", &n);
        if (n == 0) {
            break;
        }

        int eatWays = countEatWays(n);
        printf("%d\n", eatWays);
    }

    return 0;
}

在上述代码中,我们定义了 countEatWays 函数来计算给定糖果数目下的吃法总数。我们使用动态规划的思想,从 0 到 n 遍历,计算每个数目下的吃法总数并存储在 dp 数组中。

main 函数中,我们使用一个循环来读取输入的糖果数目,并调用 countEatWays 函数来计算吃法总数,并将结果输出。当输入的糖果数目为 0 时,表示测试结束,循环终止。

编译并运行上述的代码可以解决该问题。你可以使用 C 语言编译器将代码保存为 .c 文件,然后编译并运行该文件来获取结果。

第5题:放苹果

把M个同样的苹果放在N个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法?(用K表示)5,1,1和1,5,1 是同一种分法。
时间限制:1000
内存限制:65536
输入
第一行是测试数据的数目t(0 <= t <= 20)。以下每行均包含二个整数M和N,以空格分开。1<=M,N<=10。
输出
对输入的每组数据M和N,用一行输出相应的K。
样例输入
1
7 3
样例输出
8

这个问题可以使用递归或动态规划来解决。我们可以定义一个函数 countWays,用于计算将 M 个苹果放入 N 个盘子中的分法总数。

递归方法:

  • 如果 MN 的值为 1,表示只有一个盘子或只有一个苹果,那么只有一种分法,即将所有苹果放入一个盘子中。

  • 如果 M 小于 N,则将问题转化为将 M 个苹果放入 M 个盘子中的分法总数,因为有的盘子可能为空。

  • 否则,将问题分成两种情况:一种是至少有一个盘子为空,另一种是所有盘子都至少有一个苹果。对于第一种情况,我们可以将问题转化为将 M 个苹果放入 N-1 个盘子中的分法总数;对于第二种情况,我们可以将问题转化为将剩余的 M-N 个苹果放入 N 个盘子中的分法总数。将这两种情况的分法总数相加即可得到结果。

下面是使用 C 语言编写的递归解题代码:

#include 

int countWays(int M, int N) {
    if (M == 1 || N == 1) {
        return 1;
    } else if (M < N) {
        return countWays(M, M);
    } else {
        return countWays(M, N - 1) + countWays(M - N, N);
    }
}

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

    while (t--) {
        int M, N;
        scanf("%d %d", &M, &N);

        int ways = countWays(M, N);
        printf("%d\n", ways);
    }

    return 0;
}

在上述代码中,我们定义了 countWays 函数来递归计算将 M 个苹果放入 N 个盘子中的分法总数。在函数中,我们首先处理特殊情况,即当 MN 的值为 1 时,返回 1。然后,我们根据问题的性质进行分情况讨论,计算不同情况下的分法总数,并将结果相加返回。

main 函数中,我们首先读取测试数据的数目 t。然后,使用一个循环来读取每组数据的 MN 值,并调用 countWays 函数来计算分法总数,并将结果输出。

编译并运行上述的代码可以解决该问题。你可以使用 C 语言编译器将代码保存为 .c 文件,然后编译并运行该文件来获取结果。

你可能感兴趣的:(C/C++等级考试历届真题解析,c语言,c++,算法,等级考试,电子学会)