【GESP】C++五级真题(贪心考点) luogu-B3872 [GESP202309 五级] 巧夺大奖

GESP C++ 2023年9月五级真题,贪心算法考点,难度⭐⭐⭐☆☆。洛谷难度等级普及/提高−

luogu-B3872 [GESP202309 五级] 巧夺大奖

题目要求

题目描述

小明参加了一个巧夺大奖的游戏节目。主持人宣布了游戏规则:

  1. 游戏分为 n个时间段,参加者每个时间段可以选择一个小游戏。

  2. 游戏中共有 n个小游戏可供选择。

  3. 每个小游戏有规定的时限和奖励。对于第i个小游戏,参加者必须在第Ti个时间段结束前完成才能得到奖励Ri 。

小明发现,这些小游戏都很简单,不管选择哪个小游戏,他都能在一个时间段内完成。关键问题在于,如何安排每个时间段分别选择哪个小游戏,才能使得总奖励最高?

题目题解详见:https://www.coderli.com/gesp-5-luogu-b3872/

https://www.coderli.com/gesp-5-luogu-b3872/https://www.coderli.com/gesp-5-luogu-b3872/

### 问题解析 题目要求解决的是一个典型的贪心算法问题,核心目标是最大化总得分。每个小游戏有一个完成奖励 $ R_i $ 和一个截止时间 $ d_i $,表示该游戏必须在截止时间之前(包含该时间点)完成。每轮游戏只能进行一次,并且每一轮只能完成一个任务。 为了解决这个问题,可以采用以下步骤: 1. **将所有任务按奖励从高到低排序**:优先考虑奖励高的任务,因为它们对总分贡献更大。 2. **尽可能安排任务在截止时间内完成**:维护一个标记数组,记录哪些时间点已经被占用,尝试将当前任务安排在其截止时间前的第一个可用时间点上。 ### 解题思路 - 首先读取输入数据,包括任务数量 $ n $、每个任务的截止时间和奖励值。 - 将任务存储在一个结构体或类中,并按照奖励值降序排序。 - 使用一个布尔数组 `used` 来记录哪些时间点已经被占用。 - 对于每一个任务,在其截止时间之前寻找第一个未被占用的时间点,如果找到,则分配该时间点并标记为已使用;否则,跳过此任务。 ### C++代码示例 ```cpp #include <iostream> #include <vector> #include <algorithm> using namespace std; struct Task { int reward; int deadline; }; // 比较函数,用于按奖励降序排序 bool compareTasks(const Task& a, const Task& b) { return a.reward > b.reward; } int main() { int n; cin >> n; vector<Task> tasks(n); for (int i = 0; i < n; ++i) { cin >> tasks[i].deadline; } for (int i = 0; i < n; ++i) { cin >> tasks[i].reward; } // 按照奖励降序排序 sort(tasks.begin(), tasks.end(), compareTasks); // 记录每个时间点是否已被占用 vector<bool> used(n + 2, false); // 假设最多需要n+1的时间点 long long totalScore = 0; for (const auto& task : tasks) { // 寻找可以安排的时间点 int time = task.deadline; while (time > 0 && used[time]) { --time; } if (time > 0) { used[time] = true; totalScore += task.reward; } } cout << totalScore << endl; return 0; } ``` ### 优化方向与复杂度分析 - **时间复杂度**:排序操作的时间复杂度为 $ O(n \log n) $,而任务分配过程中最坏情况下可能达到 $ O(n^2) $,例如当所有任务的截止时间相同。 - **空间复杂度**:由于使用了额外的数组来记录时间点状态,空间复杂度为 $ O(n) $。 - **进一步优化**:可以通过并查集(Disjoint Set Union, DSU)优化时间点查找过程,将内层循环的复杂度降至均摊 $ O(\alpha(n)) $,从而使整体复杂度降低至 $ O(n \log n) $。这种方法的核心思想是维护每个时间点的下一个可用位置,从而快速跳过已被占用的时间区间[^2]。 ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值