找回密码
 立即注册
查看: 18|回复: 0

2019年CSP-J 公交换乘问题详解:队列模拟与优惠券管理策略

[复制链接]
  • 打卡等级:即来则安
  • 打卡总天数:15
  • 打卡月天数:1
  • 打卡总奖励:117
  • 最近打卡:2025-08-02 15:29:27

21

主题

5

回帖

2388

积分

VIP

积分
2388
发表于 2025-7-20 11:44:43 | 显示全部楼层 |阅读模式
截图未命名.jpg
一、问题背景与需求分析

题目模拟城市交通卡优惠规则:

  • 乘坐地铁获得等额优惠券(票价×1,有效期45分钟)
  • 乘坐公交时可使用未过期优惠券抵扣
  • 计算最终总支出

‌核心难点‌:

  • 优惠券的时效性管理(45分钟有效期)
  • 优惠券使用策略(优先使用最早获得的)
  • 高效处理大量乘车记录(n ≤ 10^5)

二、完整代码实现(带详细注释)
  1. #include <iostream>
  2. #include <queue>
  3. using namespace std;

  4. // 优惠券结构体:存储面值和时间戳
  5. struct Coupon {
  6.     int price;  // 地铁票价(优惠券面值)
  7.     int time;   // 获得优惠券的时间(分钟)
  8. };

  9. int main() {
  10.     ios::sync_with_stdio(false);  // 关闭同步提升IO速度
  11.     cin.tie(nullptr);             // 解除cin与cout的绑定
  12.    
  13.     int n, total = 0;            // n:记录总数 total:总支出
  14.     cin >> n;
  15.     queue<Coupon> coupons;       // 优惠券队列(先进先出)
  16.    
  17.     for (int i = 0; i < n; ++i) {
  18.         int type, price, time;
  19.         cin >> type >> price >> time;
  20.         
  21.         if (type == 0) {  // 地铁记录
  22.             total += price;       // 地铁必须全额支付
  23.             coupons.push({price, time});  // 生成等额优惠券
  24.         }
  25.         else {  // 公交记录
  26.             // 阶段1:清理过期优惠券(队首最早)
  27.             while (!coupons.empty() && time - coupons.front().time > 45) {
  28.                 coupons.pop();  // 移除过期优惠券
  29.             }
  30.             
  31.             bool used = false;  // 标记是否找到可用优惠券
  32.             queue<Coupon> temp; // 临时队列暂存未使用的优惠券
  33.             
  34.             // 阶段2:尝试使用优惠券
  35.             while (!coupons.empty()) {
  36.                 Coupon c = coupons.front();
  37.                 coupons.pop();
  38.                
  39.                 if (!used && c.price >= price) {  // **找到可用优惠券
  40.                     used = true;  // 标记已使用(不实际扣除金额)
  41.                 }
  42.                 else {  // 未使用的优惠券暂存
  43.                     temp.push(c);
  44.                 }
  45.             }
  46.             
  47.             // 阶段3:恢复未使用的优惠券
  48.             while (!temp.empty()) {
  49.                 coupons.push(temp.front());
  50.                 temp.pop();
  51.             }
  52.             
  53.             if (!used) total += price;  // 无可用优惠券则支付
  54.         }
  55.     }
  56.    
  57.     cout << total << endl;
  58.     return 0;
  59. }
复制代码


三、算法核心思想解析
  • ‌1.队列特性应用‌:


    • 天然满足"先进先出"特性,最早获得的优惠券**被考虑
    • 队首元素永远是最早获得的优惠券

  • ‌2.三阶段处理流程‌:


    • ‌清理阶段‌:移除所有过期优惠券(时间差>45分钟)
    • ‌匹配阶段‌:寻找**个满足条件的优惠券(面值≥公交票价)
    • ‌恢复阶段‌:保留未使用的有效优惠券

  • ‌3.时间复杂度分析‌:


    • 最坏情况O(n^2)(当所有优惠券都无法使用时)
    • 实际运行效率较高(优惠券通常能及时使用)

四、优化思路与变种问题
  • ‌性能优化‌:


    • 使用双队列减少元素搬移
    • 提前终止搜索(找到可用优惠券后立即停止)

  • ‌规则变种‌:


    • 优惠券可叠加使用
    • 不同交通工具产生不同面值优惠券
    • 动态调整优惠券有效期

  • ‌实际应用扩展‌:


    • 商场优惠券管理系统
    • 会员积分兑换系统
    • 多平台优惠券聚合使用

五、常见错误与调试技巧
  • 边界条件‌:


    • 时间差刚好45分钟时的处理
    • 连续多次公交使用同一优惠券

  • ‌调试建议‌:


    • 打印优惠券队列状态
    • 记录每次操作后的总金额
    • 构造极端测试用例(如全部公交或全部地铁)

  • ‌易错点警示‌:


    • 忘记处理优惠券过期
    • 错误计算时间差
    • 优惠券使用后未正确移除

来源:信奥赛学习

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

本版积分规则

SEO网站 ( 冀ICP备2025113422号-2 )|网站地图

Powered by Discuz! X3.5

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