C/C++每日一练14

例题 1:乒乓球框

题目描述

两个乒乓球框 A 和 B,A、B 中均只包含红球和黑球。判断 B 中的球是否能被 A "完全包含",即 B 中红球数量≤A 中红球数量,且 B 中黑球数量≤A 中黑球数量。

解题思路

核心是统计 A、B 中红球和黑球的数量并比较。用枚举类型定义 "红球" 和 "黑球",替代传统的 0/1 数字,让代码逻辑更清晰。

代码实现

cpp

运行

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

// 用枚举定义球的类型,避免0/1混淆
enum class Ball { Red, Black };

// 统计字符串中红球和黑球的数量
void countBalls(const string& s, int& red, int& black) {
    red = 0;
    black = 0;
    for (char c : s) {
        if (c == 'R') {
            red++; // 枚举Ball::Red对应'R'
        } else if (c == 'B') {
            black++; // 枚举Ball::Black对应'B'
        }
    }
}

int main() {
    string A, B;
    cin >> A >> B;

    int a_red, a_black, b_red, b_black;
    countBalls(A, a_red, a_black);
    countBalls(B, b_red, b_black);

    // 判断B是否被A包含
    if (b_red <= a_red && b_black <= a_black) {
        cout << "Yes" << endl;
    } else {
        cout << "No" << endl;
    }
    return 0;
}

详细解释

  1. 枚举类型的作用 :用Ball::RedBall::Black明确标记球的类型,比直接用 0 代表红球、1 代表黑球更直观,避免后续逻辑中数字含义混淆。
  2. 统计逻辑:遍历字符串 A 和 B,通过字符 'R' 和 'B' 分别对应红球和黑球,统计数量后直接比较,满足 "B 的红球数≤A 的红球数且黑球数≤A 的黑球数" 则输出 Yes,否则 No。

例题 2:组队竞赛

题目描述

有 n 个选手,每个选手有一个能力值,要组成 m 支队伍,每支队伍 3 人。团队能力值定义为队伍中第二高的能力值,求所有队伍的团队能力值之和的最大值。

解题思路

要使总和最大,需让每支队伍的 "第二高值" 尽可能大。策略:将所有选手能力值排序后,从后往前每 3 人一组,取中间值累加。用枚举标记每组内的 "第一高""第二高""第三高" 位置,让分组逻辑更清晰。

代码实现

cpp

运行

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

// 枚举每组内的位置:第三高、第二高、第一高
enum class GroupPos { Third, Second, First };

int main() {
    int n, m;
    cin >> n >> m;
    vector<int> skills(n);
    for (int i = 0; i < n; ++i) {
        cin >> skills[i];
    }

    // 排序:从小到大
    sort(skills.begin(), skills.end());

    long long total = 0;
    int index = n - 1; // 从最后一个元素开始

    for (int i = 0; i < m; ++i) {
        // 每组3人:index(First)、index-1(Second)、index-2(Third)
        // 取Second位置的值累加
        total += skills[index - static_cast<int>(GroupPos::Second)];
        index -= 3; // 移动到下一组的First位置
    }

    cout << total << endl;
    return 0;
}

详细解释

  1. 排序与贪心策略:将能力值排序后,最大的 m 个值会被作为 "第一高",次大的 m 个值作为 "第二高",这正是我们需要累加的部分。例如 n=6,排序后为 1,2,3,4,5,6,m=2 组:第一组 4,5,6 取 5,第二组 1,2,3 取 2,总和 5+2=7。
  2. 枚举的作用 :用GroupPos::Second明确标记要取的是每组中间位置(即第二高),避免直接写index-1导致的逻辑模糊,让代码可读性更强。

例题 3:删除相邻数字最大分数

题目描述

给定一个数组,每次可以删除两个相邻且相等的数字,删除后获得这两个数字的和作为分数。重复此操作,直到无法删除,求最大可能的总分数。

解题思路

这是典型的动态规划问题,用dp[i][j]表示区间[i,j]内删除相邻相等数字能获得的最大分数。枚举区间长度和中间点 k,若arr[k] == arr[j],则可尝试合并区间[i,k-1][k+1,j-1]的删除结果,再加上2*arr[k]。用枚举标记 "可删除" 状态,让状态转移逻辑更直观。

代码实现

cpp

运行

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

// 枚举删除状态:未删除、可删除
enum class DeleteState { Undeleted, Deletable };

int main() {
    int n;
    cin >> n;
    vector<int> arr(n);
    for (int i = 0; i < n; ++i) {
        cin >> arr[i];
    }

    // dp[i][j]:区间[i,j]的最大分数
    vector<vector<int>> dp(n, vector<int>(n, 0));

    // 枚举区间长度,从2开始
    for (int len = 2; len <= n; ++len) {
        // 枚举区间起点i
        for (int i = 0; i <= n - len; ++i) {
            int j = i + len - 1; // 区间终点j
            dp[i][j] = dp[i][j-1]; // 初始化为不删除j的情况

            // 枚举中间点k,寻找与arr[j]相等的元素
            for (int k = i; k < j; ++k) {
                if (arr[k] == arr[j]) {
                    // 若k和j相邻,直接删除得2*arr[j]
                    int current = (k == j-1) ? 2*arr[j] : dp[k+1][j-1] + 2*arr[j];
                    // 加上左边区间[i,k-1]的分数
                    if (k > i) {
                        current += dp[i][k-1];
                    }
                    dp[i][j] = max(dp[i][j], current);
                }
            }
        }

    cout << dp[0][n-1] << endl;
    return 0;
}

详细解释

  1. 动态规划状态定义dp[i][j]记录从索引 i 到 j 的子数组中,删除相邻相等数字的最大分数。
  2. 枚举与状态转移 :通过枚举区间长度和中间点 k,判断arr[k]是否与arr[j]相等。若相等,说明kj可以作为一对被删除,此时分数为区间[i,k-1]的分数 + 区间[k+1,j-1]的分数 + 2*arr[k]。用枚举DeleteState可辅助标记kj是否处于 "可删除" 状态,让逻辑更清晰。
  3. 示例:数组 3,4,2,2,4,最优删除路径为:先删 2,2 得 4 分,数组变为 3,4,4;再删 4,4 得 8 分,数组变为 3,总分数 4+8=12,与 dp 04 计算结果一致。

谢谢

相关推荐
noipp1 小时前
推荐题目:洛谷 P3726 [AHOI2017/HNOI2017] 抛硬币
c语言·数据结构·c++·算法·编程·洛谷·luogu
程序员-珍1 小时前
力扣 877. 石子游戏
算法·leetcode·游戏
Kina_C1 小时前
HAProxy 负载均衡算法全解析:从静态轮询到一致性哈希的实战指南
linux·算法·负载均衡·哈希算法·haproxy
月光船幽幽1 小时前
四层公理框架驱动AI健康诊断
人工智能·python·科技·算法·安全
zmzb01031 小时前
C++课后习题训练记录Day176
开发语言·c++
王维同学2 小时前
跨位数进程的映像、命令行与环境块读取
c++·windows·安全
Rabitebla2 小时前
C++ STL 之 set 详解:从底层红黑树到实际应用
开发语言·数据结构·c++·算法·leetcode
liulilittle2 小时前
无锁多生产者多消费者队列的工程实现剖析——算法、内存模型与性能
算法·多线程·并发·无锁·mpmc·lock-free
郝学胜-神的一滴2 小时前
力扣 692:巧用小顶堆高效求解前K个高频单词
java·数据结构·python·程序人生·算法·leetcode·职场和发展