查看: 35|回复: 0

2024年CSP-S决斗问题解析:贪心算法与双指针策略的巧妙应用

[复制链接]
  • TA的每日心情

    2 小时前
  • 签到天数: 29 天

    [LV.4]偶尔看看III

    29

    主题

    0

    回帖

    52

    积分

    注册会员

    Rank: 2

    积分
    52
    发表于 2025-6-16 15:26:16 | 显示全部楼层 |阅读模式


    一、问题理解与算法选择
    题目要求计算n名选手两两决斗后最多能保留多少名选手。核心思路是:当选手A的战斗力小于选手B时,A会被淘汰,我们需要找出最优的匹配策略。
    算法选择理由
    二、完整代码实现(带详细注释)
    1. #include <iostream>
    2. #include <vector>
    3. #include <algorithm>
    4. #include <unordered_map>
    5. using namespace std;

    6. int main() {
    7.     // 优化输入输出
    8.     ios::sync_with_stdio(false);
    9.     cin.tie(nullptr);
    10.    
    11.     // 读取选手数量
    12.     int n;
    13.     cin >> n;
    14.    
    15.     // 存储选手战斗力
    16.     vector<int> r(n);
    17.     for (int i = 0; i < n; ++i) {
    18.         cin >> r[i];
    19.     }
    20.    
    21.     // 关键步骤1:排序战斗力
    22.     sort(r.begin(), r.end());
    23.    
    24.     // 统计每个战斗力出现的频率(虽然本题未直接使用)
    25.     unordered_map<int, int> freq;
    26.     for (int num : r) {
    27.         freq[num]++;
    28.     }
    29.    
    30.     // 初始假设所有选手都会被保留
    31.     int res = n;
    32.    
    33.     // 双指针初始化
    34.     int i = 0, j = 1;
    35.    
    36.     // 关键步骤2:贪心匹配
    37.     while (i < n && j < n) {
    38.         if (r[i] < r[j]) {  // 找到可以淘汰i的j
    39.             res--;          // 淘汰i选手
    40.             i++;            // 处理下一个最小选手
    41.             j++;            // j也需要移动
    42.         } else {            // 当前j不足以淘汰i
    43.             j++;            // 尝试更大的j
    44.         }
    45.     }
    46.    
    47.     // 输出最终保留的选手数量
    48.     cout << res << endl;
    49.    
    50.     return 0;
    51. }
    复制代码

    • 将选手按战斗力升序排列
    • 使得我们可以用贪心策略依次处理

    指针策略

    • i指针追踪当前最小战斗力选手
    • j指针寻找可以淘汰i的选手

    淘汰逻辑

    • 当r < r[j]时完成一次有效淘汰
    • 每次淘汰后两个指针都向前移动
    • 否则只移动j指针寻找更大战斗力的选手


    原文:2024年CSP-S决斗问题解析:贪心算法与双指针策略的巧妙应用

    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    快速回复 返回顶部 返回列表