电子学会C/C++编程等级考试2023年05月(四级)真题解析

C/C++等级考试(1~8级)全部真题・点这里

第1题:怪盗基德的滑翔翼

怪盗基德是一个充满传奇色彩的怪盗,专门以珠宝为目标的超级盗窃犯。而他最为突出的地方,就是他每次都能逃脱中村警部的重重围堵,而这也很大程度上是多亏了他随身携带的便于操作的滑翔翼。

有一天,怪盗基德像往常一样偷走了一颗珍贵的钻石,不料却被柯南小朋友识破了伪装,而他的滑翔翼的动力装置也被柯南踢出的足球破坏了。不得已,怪盗基德只能操作受损的滑翔翼逃脱。

假设城市中一共有N幢建筑排成一条线,每幢建筑的高度各不相同。初始时,怪盗基德可以在任何一幢建筑的顶端。他可以选择一个方向逃跑,但是不能中途改变方向(因为中森警部会在后面追击)。因为滑翔翼动力装置受损,他只能往下滑行(即:只能从较高的建筑滑翔到较低的建筑)。他希望尽可能多地经过不同建筑的顶部,这样可以减缓下降时的冲击力,减少受伤的可能性。请问,他最多可以经过多少幢不同建筑的顶部(包含初始时的建筑)?
输入

输入数据第一行是一个整数K(K < 100),代表有K组测试数据。 每组测试数据包含两行:第一行是一个整数N(N < 100),代表有N幢建筑。第二行包含N个不同的整数,每一个对应一幢建筑的高度h(0 < h < 10000),按照建筑的排列顺序给出。
输出

对于每一组测试数据,输出一行,包含一个整数,代表怪盗基德最多可以经过的建筑数量。
样例输入

3

8

300 207 155 299 298 170 158 65

8

65 158 170 298 299 155 207 300

10

2 1 3 4 5 6 7 8 9 10
样例输出

6

6

9

以下是一个解决这个问题的C++程序示例:

c 复制代码
#include <iostream>
#include <vector>
using namespace std;

int getMaxBuildings(vector<int>& heights) {
    int maxBuildings = 1;
    int maxHeight = heights[0];
    
    for (int i = 1; i < heights.size(); i++) {
        if (heights[i] > maxHeight) {
            maxBuildings++;
            maxHeight = heights[i];
        }
    }
    
    return maxBuildings;
}

int main() {
    int k;
    cin >> k;
    
    for (int i = 0; i < k; i++) {
        int n;
        cin >> n;
        
        vector<int> heights(n);
        for (int j = 0; j < n; j++) {
            cin >> heights[j];
        }
        
        int maxBuildings = getMaxBuildings(heights);
        cout << maxBuildings << endl;
    }
    
    return 0;
}

该程序使用一个循环来处理每组测试数据。对于每组测试数据,首先读取建筑数量n,然后读取n个不同的整数,表示每幢建筑的高度。接下来,使用一个循环遍历建筑高度,并通过比较当前建筑高度与之前最高建筑的高度来确定是否可以经过该建筑。如果当前建筑高度大于之前最高建筑的高度,那么可以经过该建筑,并将最大建筑数量加1,并更新最高建筑的高度。最后,输出最大建筑数量作为结果。程序根据输入的测试数据组数k,循环读取每组测试数据,并输出对应的结果。

第2题:数字组合

有n个正整数,找出其中和为t(t也是正整数)的可能的组合方式。如: n=5,5个数分别为1,2,3,4,5,t=5; 那么可能的组合有5=1+4和5=2+3和5=5三种组合方式。
输入

输入的第一行是两个正整数n和t,用空格隔开,其中1<=n<=20,表示正整数的个数,t为要求的和(1<=t<=1000) 接下来的一行是n个正整数,用空格隔开。
输出

和为t的不同的组合方式的数目。
样例输入

5 5

1 2 3 4 5
样例输出

3

以下是一个解决这个问题的C++程序示例:

c 复制代码
#include <iostream>
#include <vector>
using namespace std;

int countCombinations(vector<int>& nums, int target) {
    int n = nums.size();
    vector<vector<int>> dp(n + 1, vector<int>(target + 1, 0));
    
    // 初始化第一列,表示和为0的组合数为1
    for (int i = 0; i <= n; i++) {
        dp[i][0] = 1;
    }
    
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= target; j++) {
            // 如果当前数字大于目标和,则不能选择该数字
            if (nums[i - 1] > j) {
                dp[i][j] = dp[i - 1][j];
            } else {
                // 选择当前数字和不选择当前数字两种情况的组合数之和
                dp[i][j] = dp[i - 1][j] + dp[i - 1][j - nums[i - 1]];
            }
        }
    }
    
    return dp[n][target];
}

int main() {
    int n, t;
    cin >> n >> t;
    
    vector<int> nums(n);
    for (int i = 0; i < n; i++) {
        cin >> nums[i];
    }
    
    int result = countCombinations(nums, t);
    cout << result << endl;
    
    return 0;
}

该程序使用动态规划的方法来解决问题。首先,创建一个二维数组dp,其中dp[i][j]表示使用前i个数字组成和为j的组合数。然后,初始化第一列,表示和为0的组合数为1。接下来,使用两个嵌套循环遍历数组和目标和,根据当前数字的大小来确定选择该数字和不选择该数字两种情况下的组合数。最后,返回dp[n][target]作为结果。程序根据输入的正整数个数n和目标和t,读取n个正整数,并调用countCombinations函数计算结果,然后输出结果。

第3题:带通配符的字符串匹配

通配符是一类键盘字符,当我们不知道真正字符或者不想键入完整名字时,常常使用通配符代替一个或多个真正字符。通配符有问号(?)和星号(*)等,其中,"?"可以代替一个字符,而"*"可以代替零个或多个字符。

你的任务是,给出一个带有通配符的字符串和一个不带通配符的字符串,判断他们是否能够匹配。

例如,1?456 可以匹配 12456、13456、1a456,但是却不能够匹配23456、1aa456;2*77?8可以匹配 24457798、237708、27798。
输入

输入有两行,每行为一个不超过20个字符的字符串,第一行带通配符,第二行不带通配符
输出

如果两者可以匹配,就输出"matched",否则输出"not matched"
样例输入

1*456?

11111114567
样例输出

matched

以下是一个解决这个问题的C++程序示例:

c 复制代码
#include <iostream>
#include <string>
using namespace std;

bool isMatched(string pattern, string text) {
    int m = pattern.length();
    int n = text.length();
    
    // 创建一个二维数组dp,dp[i][j]表示pattern的前i个字符和text的前j个字符是否匹配
    vector<vector<bool>> dp(m + 1, vector<bool>(n + 1, false));
    
    // 初始化dp[0][0]为true,表示空字符串匹配
    dp[0][0] = true;
    
    // 处理pattern以*开头的情况
    for (int i = 1; i <= m; i++) {
        if (pattern[i - 1] == '*') {
            dp[i][0] = dp[i - 1][0];
        }
    }
    
    // 动态规划计算匹配情况
    for (int i = 1; i <= m; i++) {
        for (int j = 1; j <= n; j++) {
            if (pattern[i - 1] == '?' || pattern[i - 1] == text[j - 1]) {
                dp[i][j] = dp[i - 1][j - 1];
            } else if (pattern[i - 1] == '*') {
                dp[i][j] = dp[i - 1][j] || dp[i][j - 1];
            }
        }
    }
    
    return dp[m][n];
}

int main() {
    string pattern, text;
    cin >> pattern >> text;
    
    bool matched = isMatched(pattern, text);
    if (matched) {
        cout << "matched" << endl;
    } else {
        cout << "not matched" << endl;
    }
    
    return 0;
}

该程序使用动态规划的方法来解决问题。首先,创建一个二维数组dp,其中dp[i][j]表示pattern的前i个字符和text的前j个字符是否匹配。然后,初始化dp[0][0]为true,表示空字符串匹配。接下来,处理pattern以开头的情况,如果pattern的第一个字符是,则将dp[i][0]设置为dp[i-1][0]。然后,使用两个嵌套循环遍历pattern和text的字符,根据当前字符的情况来确定匹配情况。如果当前字符是?或者与text的当前字符相等,则将dp[i][j]设置为dp[i-1][j-1]。如果当前字符是*,则将dp[i][j]设置为dp[i-1][j]或者dp[i][j-1]的逻辑或。最后,返回dp[m][n]作为结果。程序根据输入的带通配符的字符串和不带通配符的字符串,调用isMatched函数判断是否匹配,并输出结果。

第4题:股票买卖

最近越来越多的人都投身股市,阿福也有点心动了。谨记着"股市有风险,入市需谨慎",阿福决定先来研究一下简化版的股票买卖问题。

假设阿福已经准确预测出了某只股票在未来 N 天的价格,他希望买卖两次,使得获得的利润最高。为了计算简单起见,利润的计算方式为卖出的价格减去买入的价格。

同一天可以进行多次买卖。但是在第一次买入之后,必须要先卖出,然后才可以第二次买入。

现在,阿福想知道他最多可以获得多少利润。
输入

输入的第一行是一个整数 T (T <= 50) ,表示一共有 T 组数据。 接下来的每组数据,第一行是一个整数 N (1 <= N <= 100, 000) ,表示一共有 N 天。第二行是 N 个被空格分开的整数,表示每天该股票的价格。该股票每天的价格的绝对值均不会超过 1,000,000 。
输出

对于每组数据,输出一行。该行包含一个整数,表示阿福能够获得的最大的利润。
样例输入

3

7

5 14 -2 4 9 3 17

6

6 8 7 4 1 -2

4

18 9 5 2
样例输出

28

2

0
提示:对于第一组样例,阿福可以第 1 次在第 1 天买入(价格为 5 ),然后在第 2 天卖出(价格为 14 )。第 2 次在第 3 天买入(价格为 -2 ),然后在第 7 天卖出(价格为 17 )。一共获得的利润是 (14 - 5) + (17 - (-2)) = 28 对于第二组样例,阿福可以第 1 次在第 1 天买入(价格为 6 ),然后在第 2 天卖出(价格为 8 )。第 2 次仍然在第 2 天买入,然后在第 2 天卖出。一共获得的利润是 8 - 6 = 2 对于第三组样例,由于价格一直在下跌阿福可以随便选择一天买入之后迅速卖出。获得的最大利润为 0

下面是一个C++的实现示例:

c 复制代码
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int maxProfit(vector<int>& prices) {
    int n = prices.size();
    if (n <= 1) {
        return 0;
    }
    
    vector<int> buy(n, 0);
    vector<int> sell(n, 0);
    
    buy[0] = -prices[0];
    sell[0] = 0;
    
    for (int i = 1; i < n; i++) {
        buy[i] = max(buy[i-1], -prices[i]);
        sell[i] = max(sell[i-1], buy[i-1] + prices[i]);
    }
    
    return sell[n-1];
}

int main() {
    int T;
    cin >> T;
    
    while (T--) {
        int N;
        cin >> N;
        
        vector<int> prices(N);
        for (int i = 0; i < N; i++) {
            cin >> prices[i];
        }
        
        int max_profit = maxProfit(prices);
        cout << max_profit << endl;
    }
    
    return 0;
}

这是一个动态规划问题。我们可以使用两个数组来记录买入和卖出的最大利润。假设buy[i]表示在第i天之前进行一次买入操作所能获得的最大利润,sell[i]表示在第i天之前进行一次卖出操作所能获得的最大利润。

对于buy[i],我们可以选择在第i天买入股票,或者不进行任何操作。如果选择在第i天买入股票,那么buy[i] = max(buy[i-1], -prices[i]),即前一天的买入利润和在第i天买入的利润的较大值。如果选择不进行任何操作,那么buy[i] = buy[i-1]。

对于sell[i],我们可以选择在第i天卖出股票,或者不进行任何操作。如果选择在第i天卖出股票,那么sell[i] = max(sell[i-1], buy[i-1] + prices[i]),即前一天的卖出利润和在第i天卖出的利润的较大值。如果选择不进行任何操作,那么sell[i] = sell[i-1]。

最后,我们的目标是求得最大利润,即max(sell[N-1]),其中N为天数。

相关推荐
我们的五年几秒前
【Linux课程学习】:进程描述---PCB(Process Control Block)
linux·运维·c++
张彦峰ZYF1 分钟前
投资策略规划最优决策分析
分布式·算法·金融
-一杯为品-6 分钟前
【51单片机】程序实验5&6.独立按键-矩阵按键
c语言·笔记·学习·51单片机·硬件工程
The_Ticker16 分钟前
CFD平台如何接入实时行情源
java·大数据·数据库·人工智能·算法·区块链·软件工程
程序猿阿伟17 分钟前
《C++ 实现区块链:区块时间戳的存储与验证机制解析》
开发语言·c++·区块链
爪哇学长1 小时前
双指针算法详解:原理、应用场景及代码示例
java·数据结构·算法
爱摸鱼的孔乙己1 小时前
【数据结构】链表(leetcode)
c语言·数据结构·c++·链表·csdn
Dola_Pan1 小时前
C语言:数组转换指针的时机
c语言·开发语言·算法
繁依Fanyi1 小时前
简易安卓句分器实现
java·服务器·开发语言·算法·eclipse
烦躁的大鼻嘎1 小时前
模拟算法实例讲解:从理论到实践的编程之旅
数据结构·c++·算法·leetcode