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 计算结果一致。

谢谢

相关推荐
Jared_devin7 分钟前
单头、多头 Self-Attention可视化
人工智能·pytorch·深度学习·算法·机器学习·pycharm
Jackson_GJH15 分钟前
C++虚函数、虚继承、虚基类
c++·c++基础
wuyk55518 分钟前
18.Kruskal 算法:用最短的边连成一张网
开发语言·算法·图论
码匠许师傅31 分钟前
【C++三方组件】开篇总论:为什么需要以及如何选型?
开发语言·c++
h_a_o777oah37 分钟前
【Games101】C++ 软光追:光线追踪的求交逻辑和 BVH 提效实现及代码实现细节
c++·计算机图形学·光线追踪·games101·bvh·求交算法·软件渲染
cvby1 小时前
C++11--右值引用和移动语义
开发语言·c++
pen-ai1 小时前
【优化方法】最小二乘:从误差平方到线性与非线性拟合
人工智能·算法·机器学习
xiangyun611 小时前
【408数据结构 03】线性表与顺序表:C++手写SeqList
开发语言·数据结构·c++
君科程序定做2 小时前
用 IDL 处理高分一号(GF-1 / GF-1B/C/D)数据
c语言·开发语言
Q26433650232 小时前
【有源码】基于机器学习的电信网络诈骗话术语义识别与可视化分析系统 XGBoost算法+Hadoop+Spark
大数据·hadoop·算法·机器学习·spark·毕业设计·课程设计