19339201706 发表于 2025-6-16 15:26:16

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

https://dajuwangluo.cn/zb_users/upload/2025/06/202506081749361936262620.jpg

一、问题理解与算法选择题目要求计算n名选手两两决斗后最多能保留多少名选手。核心思路是:当选手A的战斗力小于选手B时,A会被淘汰,我们需要找出最优的匹配策略。算法选择理由:
[*]贪心算法:总希望当前最小的选手能匹配到刚好比它大的对手
[*]双指针技巧:高效遍历已排序数组的最佳选择
[*]时间复杂度:O(nlogn) 主要来自排序操作
二、完整代码实现(带详细注释)
#include <iostream>
#include <vector>
#include <algorithm>
#include <unordered_map>
using namespace std;

int main() {
    // 优化输入输出
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
   
    // 读取选手数量
    int n;
    cin >> n;
   
    // 存储选手战斗力
    vector<int> r(n);
    for (int i = 0; i < n; ++i) {
      cin >> r;
    }
   
    // 关键步骤1:排序战斗力
    sort(r.begin(), r.end());
   
    // 统计每个战斗力出现的频率(虽然本题未直接使用)
    unordered_map<int, int> freq;
    for (int num : r) {
      freq++;
    }
   
    // 初始假设所有选手都会被保留
    int res = n;
   
    // 双指针初始化
    int i = 0, j = 1;
   
    // 关键步骤2:贪心匹配
    while (i < n && j < n) {
      if (r < r) {// 找到可以淘汰i的j
            res--;          // 淘汰i选手
            i++;            // 处理下一个最小选手
            j++;            // j也需要移动
      } else {            // 当前j不足以淘汰i
            j++;            // 尝试更大的j
      }
    }
   
    // 输出最终保留的选手数量
    cout << res << endl;
   
    return 0;
}

[*]将选手按战斗力升序排列
[*]使得我们可以用贪心策略依次处理
双指针策略:

[*]i指针追踪当前最小战斗力选手
[*]j指针寻找可以淘汰i的选手
淘汰逻辑:

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

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

页: [1]
查看完整版本: 2024年CSP-S决斗问题解析:贪心算法与双指针策略的巧妙应用