P5661 [CSP-J2019] 公交换乘
P5661 [CSP-J2019] 公交换乘 解题分析与代码注释
解题思路
这道题目需要模拟公交和地铁的换乘优惠规则,主要考察对队列的应用和优惠券管理的能力。以下是解题的关键点:
-
数据结构选择:使用数组模拟队列来存储优惠券信息。虽然STL的queue更简单,但本题需要频繁遍历队列中的元素(检查可用优惠券),而STL queue不支持随机访问,因此手动实现队列更高效。
-
优惠券管理:
-
乘地铁时获得优惠券(入队)
-
乘公交时查找最早可用的优惠券(遍历队列)
-
定期清理过期的优惠券(出队)
-
-
时间限制:优惠券有效期为45分钟,需要及时清理过期优惠券以减少不必要的遍历。
-
使用规则:公交必须使用可用的最早优惠券,且优惠券金额必须大于等于公交票价。
代码注释
#include<bits/stdc++.h> using namespace std; // 定义优惠券结构体 struct node{ int t,p,f; // t:优惠券获取时间,p:可抵扣金额,f:是否使用过(0未使用,1已使用) }; node q[1000010]; // 用数组模拟队列存储优惠券 int head,tail; // 队列头尾指针,head指向队首,tail指向队尾下一个位置 int n,ans; // n:乘车记录数量,ans:总花费 int main() { cin >> n; for(int i = 1; i <= n; i++) { int op,p,t; // op:交通类型(0地铁/1公交),p:票价,t:乘车时间 cin >> op >> p >> t; if(op == 0) // 地铁乘车记录 { ans += p; // 地铁必须付费,直接加到总花费 q[tail++] = {t,p,0}; // 获得优惠券,入队(存储时间、票价、未使用状态) } if(op == 1) // 公交乘车记录 { int f = 0; // 标记是否找到可用优惠券,初始为0(未找到) // 遍历队列查找可用优惠券 for(int j = head; j < tail; j++){ // 检查优惠券是否满足条件: // 1.在45分钟内(t - q[j].t <= 45) // 2.优惠券金额足够(q[j].p >= p) // 3.未被使用过(q[j].f == 0) if(t - q[j].t <= 45 && q[j].p >= p && q[j].f == 0){ q[j].f = 1; // 标记该优惠券为已使用 f = 1; // 标记已找到优惠券 break; // 找到最早可用的就停止 } } if(f == 0) ans += p; // 没找到可用优惠券,需支付公交费 // 清理过期优惠券(超过45分钟的) while(head < tail && t - q[head].t > 45) head++; } } cout << ans; // 输出总花费 return 0; }
为什么不使用STL的queue
-
遍历需求:题目要求公交乘车时必须查找最早可用的优惠券,这需要遍历队列中的元素。STL的queue不支持随机访问,只能访问队首和队尾。
-
高效清理:需要定期清理过期的优惠券,手动实现的队列可以更高效地进行批量出队操作。
-
性能考虑:对于大规模数据(n≤10^5),手动实现的数组队列比STL queue有更好的性能表现,减少了容器操作的开销。
-
状态修改:需要在遍历过程中修改队列元素的使用状态(f字段),手动实现的队列可以更方便地进行这种操作。
通过手动实现队列,我们可以更灵活地处理优惠券的查找、使用和清理操作,满足题目要求的各项规则

浙公网安备 33010602011771号