当前位置:首页 > 入门组 > CSP-J 2019公交换乘题解析:基于队列优化的动态规划代码详解

CSP-J 2019公交换乘题解析:基于队列优化的动态规划代码详解

15小时前

CSP-J 2019公交换乘题解析:基于队列优化的动态规划代码详解 2019 公交换乘题 队列优化 动态规划 时间复杂度 第1张

一、题目解读

CSP-J 2019年的“公交换乘”题目(洛谷P5661)要求模拟地铁与公交交替出行的费用计算。题目核心在于地铁消费会产生优惠券,而公交可在45分钟内使用优惠券抵扣车费。需要处理n条出行记录,优化总费用。该问题考察对时间窗口与动态资源管理的理解,需平衡实时状态更新与历史数据利用。

二、解题思路

代码采用“队列+动态规划”策略:

    1. 使用队列存储优惠券,遵循“先进先出”原则,确保优惠券按获取时间排序

    2. 地铁消费时生成新券并入队,公交消费时检查队首券是否过期:

        过期券出队,避免无效抵扣。

        遍历剩余券,优先使用面值≥公交费用的券,首次匹配成功即停止(贪心策略)。

    3. 未使用券暂存临时队列,最终恢复至主队列,维持原顺序。

此思路将时间复杂度控制在O(n),避免重复遍历,同时保证状态一致性。

三、解题步骤

1. 输入处理:读取n条记录,每条含类型(0/1)、费用、时间。

2. 地铁处理(type=0):

    累加费用至总账。

    生成新券(面值=费用,时间=当前时间)入队。

3. 公交处理(type=1):

    清理过期券。

    循环优惠券队列:

        若券面值≥公交费且未使用过,标记使用并跳出循环。

        否则将券暂存临时队列。

        若未找到可用券,累加公交费至总账。

    将临时队列券恢复至主队列。

4. 输出总费用。

四、代码与注释

#include <iostream>  
#include <queue>  
using namespace std;  

struct Coupon {  
    int price;  // 地铁票价(优惠券面值)  
    int time;   // 获得优惠券的时间  
};  

int main() {  
    ios::sync_with_stdio(false);  // 加快输入输出  
    cin.tie(nullptr);           
  
    int n, total = 0;  
    cin >> n;  
    queue<Coupon> coupons;  // 优惠券队列(先进先出)  

    for (int i = 0; i < n; ++i) {  
        int type, price, time;  
        cin >> type >> price >> time;  

        if (type == 0) {  // 地铁记录  
            total += price;  // 地铁必须付费  
            coupons.push({price, time});  // 生成优惠券  
        }  
        else {  // 公交记录  
            // 移除过期优惠券(队首是最早的)  
            while (!coupons.empty() && time - coupons.front().time > 45) {  
                coupons.pop();  
            }  

            bool used = false;  
            // 临时队列用于恢复未使用的优惠券  
            queue<Coupon> temp;  

            // 尝试使用优惠券  
            while (!coupons.empty()) {  
                Coupon c = coupons.front();  
                coupons.pop();  

                if (!used && c.price >= price) {  // 找到可用优惠券  
                    used = true;  // 标记已使用  
                }  
                else {  // 未使用的优惠券暂存  
                    temp.push(c);  
                }  
            }  

            // 恢复未使用的优惠券  
            while (!temp.empty()) {  
                coupons.push(temp.front());  
                temp.pop();  
            }  

            if (!used) total += price;  // 没有可用优惠券则付费  
        }  
    }  

    cout << total << endl;  
    return 0;  
}

代码核心逻辑:通过队列维护优惠券时效性,利用贪心策略优先消耗高面值券,确保每个公交费用最小化。

五、总结

该解法巧妙运用队列实现“时间窗口”管理,结合动态规划思想降低复杂度。关键点在于:

    1. 优惠券队列的FIFO特性自动维护时效。

    2. 临时队列保障未使用券的状态还原。

    3. 单次公交消费仅需遍历当前有效券,避免全局搜索。

此思路为处理带时间限制的资源复用问题提供了经典模板,适用于类似场景的算法设计。

原创内容 转载请注明出处

分享给朋友:

相关文章

70.爬楼梯|三步破解动态规划核心奥秘

70.爬楼梯|三步破解动态规划核心奥秘

题意新解:站在楼梯底仰望n级台阶,每步可选1或2阶,最终的路径组合犹如斐波那契数列般展开。比如到达第3阶的路径可由第1阶跨两步,或第2阶跨一步构成,这种递推规律揭示了两两相邻状态间的紧密关联。思路解析...

IOI 1994 洛谷1216:如何用动态规划高效解决数字三角形问题?附完整代码解析

IOI 1994 洛谷1216:如何用动态规划高效解决数字三角形问题?附完整代码解析

题目重解给定一个由数字组成的三角形结构,从顶部出发,每次可以移动到下方相邻的数字,最终到达底部。我们的目标是找到一条路径,使得路径上经过的数字总和最大。这个问题在实际中有许多应用场景,如最优路径规划、...

IOI 1994 洛谷1216:如何用O(1)空间解决数字三角形问题?附代码实现

IOI 1994 洛谷1216:如何用O(1)空间解决数字三角形问题?附代码实现

题目重解:数字三角形是一个经典的动态规划问题,给定一个由数字组成的三角形结构,从顶部出发,每次可以移动到下方相邻的数字,最终到达底部。我们需要找到一条路径,使得路径上经过的数字总和最大。这个问题可以很...

从零到一掌握背包问题:洛谷P1164题解精讲,附带优化

从零到一掌握背包问题:洛谷P1164题解精讲,附带优化

题目重解:小A带着m元钱来到餐馆,菜单上有n道菜,每道菜都有确定的价格。现在需要计算出刚好花完m元的点菜方案总数。这个问题看似简单,但当菜品数量增多时,暴力枚举就会变得不可行,需要更高效的算法来解决。...

CSP-J 2019纪念品题解(洛谷P5662):动态规划+完全背包问题的实战应用

CSP-J 2019纪念品题解(洛谷P5662):动态规划+完全背包问题的实战应用

一、题目解读2019年CSP-J的“纪念品”问题(对应洛谷P5662)要求玩家在T天内通过买卖纪念品最大化金币收益。每天可交易N种商品,需计算最优策略下的最终金币数。题目强调动态规划思维与资源分配优化...

NOIP 2008火柴棒等式题解(C++代码实现)  动态规划与枚举算法详解

NOIP 2008火柴棒等式题解(C++代码实现) 动态规划与枚举算法详解

一、题目解读火柴棒等式问题(NOIP 2008,洛谷P1149)要求使用给定数量的火柴棒,构造形如 A + B = C 的等式,其中A、B、C均为整数,且火柴棒总数恰好等于输入值。需统计符合条件的等式...

发表评论

访客

看不清,换一张

◎欢迎参与讨论,请在这里发表您的看法和观点。