news 2026/11/3 3:12:49

USACO洗碗问题解析:栈的应用与算法实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
USACO洗碗问题解析:栈的应用与算法实现

1. 题目背景与需求分析

这道P6099 [USACO19FEB] Dishwashing G题目来自美国计算机奥林匹克竞赛(USACO)2019年2月银组比赛。题目描述了一个洗碗场景:有N个盘子需要清洗,每个盘子有一个污垢值d_i。洗碗机每次可以放入一个盘子,当放入新盘子时,如果当前洗碗机中最上面的盘子污垢值比新盘子小,就必须先取出所有这样的盘子才能放入新盘子。我们需要模拟这个过程,并计算总共需要多少次操作。

这类栈模拟问题在信息学竞赛中非常典型,主要考察选手对栈这种数据结构的理解和应用能力。题目中隐含的关键点在于:

  • 操作次数的计算规则(每次放入和取出都算一次操作)
  • 栈的LIFO(后进先出)特性
  • 对题目描述的准确理解和建模能力

2. 解题思路与算法设计

2.1 问题建模

我们可以将洗碗机抽象为一个栈结构,每个盘子的放入和取出对应栈的push和pop操作。根据题目描述,我们需要维护以下规则:

  1. 每次只能操作最顶端的盘子(栈顶元素)
  2. 新盘子放入前,必须确保栈顶盘子的污垢值不小于新盘子
  3. 每次操作(放入或取出)都计入总操作次数

2.2 算法选择

这个问题最适合使用栈来模拟整个过程。具体算法步骤如下:

  1. 初始化一个空栈和操作计数器(初始为0)
  2. 按顺序处理每个盘子: a. 检查栈顶元素是否小于当前盘子 b. 如果是,则不断弹出栈顶元素,直到不满足条件或栈为空(每次弹出操作计数器+1) c. 将当前盘子压入栈中(操作计数器+1)
  3. 最后,将栈中剩余的所有盘子依次弹出(每次弹出操作计数器+1)
  4. 返回总操作次数

这个算法的时间复杂度是O(N),因为每个盘子最多被压入和弹出各一次。

3. C++代码实现

3.1 基础实现

#include <iostream> #include <stack> using namespace std; int main() { int N; cin >> N; stack<int> dishStack; int operations = 0; for (int i = 0; i < N; ++i) { int d; cin >> d; while (!dishStack.empty() && dishStack.top() < d) { dishStack.pop(); operations++; } dishStack.push(d); operations++; } // 弹出剩余所有盘子 while (!dishStack.empty()) { dishStack.pop(); operations++; } cout << operations << endl; return 0; }

3.2 代码优化

我们可以做两个小优化:

  1. 避免最后单独弹出所有盘子,可以在输入处理时就完成所有操作
  2. 使用更快的输入输出方式(对于竞赛编程很重要)

优化后的代码:

#include <iostream> #include <stack> using namespace std; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int N; cin >> N; stack<int> dishStack; int operations = 0; for (int i = 0; i < N; ++i) { int d; cin >> d; while (!dishStack.empty() && dishStack.top() < d) { dishStack.pop(); operations++; } dishStack.push(d); operations++; } operations += dishStack.size(); // 剩余盘子需要弹出 cout << operations << '\n'; return 0; }

4. 测试用例与验证

4.1 示例测试

考虑USACO提供的样例输入:

5 3 2 4 1 5

处理过程:

  1. 放入3(操作1)
  2. 放入2(操作2)
  3. 放入4:需要先弹出2(操作3),弹出3(操作4),然后放入4(操作5)
  4. 放入1(操作6)
  5. 放入5:需要先弹出1(操作7),弹出4(操作8),然后放入5(操作9)
  6. 弹出5(操作10)

总操作次数:10,与样例输出一致。

4.2 边界测试

需要考虑的特殊情况:

  1. 只有一个盘子:操作次数应为2(放入+弹出)
  2. 所有盘子污垢值相同:操作次数为2N(每个盘子放入和弹出各一次)
  3. 盘子按降序排列:操作次数为N+1(放入所有盘子后一次性弹出)

5. 算法分析与复杂度

5.1 时间复杂度

每个盘子最多被压入和弹出栈各一次,因此时间复杂度是O(N)。这是最优的解法,因为我们必须至少处理每个盘子一次。

5.2 空间复杂度

最坏情况下,所有盘子可能都在栈中(当输入序列是严格递增时),因此空间复杂度也是O(N)。

5.3 算法正确性证明

我们可以用循环不变量来证明算法的正确性:

  • 不变量:栈中的盘子污垢值总是非递增的(从栈底到栈顶)
  • 初始化:空栈满足这个条件
  • 保持:每次放入新盘子前,我们会弹出所有比它小的盘子,因此放入后仍然保持非递增顺序
  • 终止:最后栈中盘子按非递增顺序排列,可以依次弹出

6. 竞赛编程技巧

6.1 输入输出优化

在USACO等竞赛中,输入输出可能是性能瓶颈。建议:

  • 使用ios::sync_with_stdio(false);和cin.tie(nullptr);加速C++的输入输出
  • 对于大量数据,考虑使用更快的输入方法(如自己实现读取函数)

6.2 调试技巧

这类模拟题容易因为边界条件出错,建议:

  1. 用小规模数据手工模拟
  2. 打印中间状态(如每次操作后的栈内容)
  3. 特别注意空栈的情况(.top()在空栈上调用会导致运行时错误)

6.3 常见错误

  1. 忘记统计弹出操作次数
  2. 没有处理最后栈中剩余的盘子
  3. 错误理解题目条件(注意是"小于"而不是"小于等于")
  4. 使用错误的数据结构(如队列或优先队列)

7. 类似题目推荐

掌握了这道题后,可以尝试以下类似题目巩固栈的应用:

  1. POJ 2559 - Largest Rectangle in Histogram(直方图最大矩形)
  2. LeetCode 739 - Daily Temperatures(每日温度)
  3. Codeforces 5C - Longest Regular Bracket Sequence(最长合法括号序列)
  4. USACO 2019 January Silver - Grass Planting(草地种植)
  5. LeetCode 84 - Largest Rectangle in Histogram(与POJ 2559相同)

8. 栈的扩展应用

栈在算法竞赛中有广泛应用,主要包括:

  1. 表达式求值(中缀转后缀)
  2. 括号匹配问题
  3. 单调栈(如本题的应用)
  4. 深度优先搜索(DFS)的非递归实现
  5. 函数调用栈的模拟

理解栈的LIFO特性是解决这类问题的关键。在实际编程中,STL的stack容器提供了方便的接口,但需要注意:

  • top()前必须检查栈是否为空
  • pop()不返回栈顶元素(需要先top()再pop())
  • 栈没有迭代器,不能遍历栈中所有元素

9. 个人实战经验

在解决这类栈模拟问题时,我总结了几个实用技巧:

  1. 先用小例子手工模拟,确保理解题意
  2. 在代码中加入调试输出(如打印每次操作后的栈状态)
  3. 特别注意边界条件:空栈、第一个/最后一个元素、所有元素相同等情况
  4. 对于操作计数类问题,明确什么算一次操作(有时放入和弹出都算,有时只算一种)
  5. 在竞赛中,如果时间允许,可以写一个暴力解法作为对拍程序

这道题的一个变种可能是询问某个特定盘子被操作的时间点,或者允许并行操作等。理解基础解法后,可以尝试思考这些扩展问题。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/11/3 3:11:53

联合类型与枚举在编程中的实战应用

1. 嘎嘎滴辣虾自定义类型解析&#xff1a;从联合到枚举的编程实践在编程语言设计中&#xff0c;自定义类型系统一直是提升代码表达力的核心武器。最近在开发"嘎嘎滴辣虾"这个美食推荐系统时&#xff0c;我深刻体会到联合(Union)和枚举(Enum)这两种自定义类型在实际工…

作者头像 李华
网站建设 2026/11/3 3:11:28

专科生论文写作工具对比:千笔写作与Checkjie评测

1. 项目概述&#xff1a;专科生论文写作工具对比评测作为一名在学术写作领域摸爬滚打多年的老手&#xff0c;我见过太多专科同学在论文写作中踩坑。今天要对比的两款工具——千笔写作和Checkjie&#xff0c;都是近期在专科生群体中热议的AI写作辅助神器。不同于通用型写作软件&…

作者头像 李华
网站建设 2026/11/3 3:11:16

Docker Compose编排Spring Boot与PostgreSQL实战指南

1. 项目概述在微服务架构盛行的当下&#xff0c;如何高效管理多容器应用成为开发者必须掌握的技能。这个项目演示了使用Docker Compose编排Spring Boot应用与PostgreSQL数据库的标准方案&#xff0c;这也是目前Java后端开发中最常见的容器化组合之一。我将在本文中分享从零开始…

作者头像 李华
网站建设 2026/11/3 3:11:11

开源自动化运维平台Oh My Opencode核心功能解析

1. Oh My Opencode项目概述Oh My Opencode是一个开源的自动化运维平台&#xff0c;它通过多个agent&#xff08;代理程序&#xff09;协同工作来实现分布式系统的集中管理。这个项目特别适合中小型企业的运维团队使用&#xff0c;能够显著降低日常维护工作的复杂度。我第一次接…

作者头像 李华
网站建设 2026/11/3 3:10:52

Oracle PDB创建与管理全攻略

1. Oracle PDB基础概念解析在Oracle 12c及更高版本中&#xff0c;多租户架构&#xff08;Multitenant Architecture&#xff09;彻底改变了传统数据库的管理模式。这个架构的核心在于将"容器"&#xff08;Container&#xff09;概念引入数据库体系&#xff0c;形成了…

作者头像 李华
网站建设 2026/11/3 3:10:47

论文写作工具链:毕业之家与PaperRed高效组合方案

1. 论文写作困境与工具选择凌晨三点的电脑屏幕前&#xff0c;咖啡杯已经见底&#xff0c;文档字数统计却还停留在三位数——这可能是每个毕业生都经历过的至暗时刻。我在指导学弟学妹论文时发现&#xff0c;90%的写作障碍并非源于学术能力&#xff0c;而是缺乏科学的写作工具链…

作者头像 李华