世界机器人大会青少年机器人设计与信息素养大赛2025-2026 学年算法应用主题赛 / 初中组wrc.hao.work
WRCWorld Robot Contest青少年算法应用训练档案馆
四大文化场景完整题库档案HTTPS 资料库
03-programming-practice/stdin-stdout-and-modules.md

标准输入输出与模块组织

很多训练题并不是因为算法不会而失分,而是因为:

关联训练题2

编程实践总览

为什么这个主题重要

很多训练题并不是因为算法不会而失分,而是因为:

  • 输入没读全
  • 输出格式多了提示语或空格
  • 解析、计算、输出混在一起,导致错了以后找不到问题点

这类错误本质上是工程组织问题。只要一开始就把程序骨架搭好,很多低级错误可以直接避免。

标准输入输出的基本规则

输入

  • 默认从标准输入读取数据
  • 不要假设输入会带中文提示语
  • 一次性读入后再解析,通常比边读边猜更稳定
  • 读题时先确认是单组数据还是多组数据

输出

  • 只输出题目要求的内容
  • 不输出“请输入”“结果为”“debug”之类提示语
  • 换行、空格、分隔符要与题面一致
  • 排序结果、格式化数值、保留位数都属于输出规范的一部分

调试时的额外原则

  • 调试信息写到日志或标准错误,不写到正式标准输出
  • 提交前必须确认所有临时打印都已删除或关闭

推荐的函数结构

对绝大多数初中组题目,下面的结构已经足够稳定:

  • parse_input:把输入文本解析成变量、数组、字典或结构体
  • solve:只处理算法逻辑
  • format_output:把答案转换成题面要求的文本
  • main:串联前三步

这样拆分的好处是:

  • 输入错了,只看 parse_input
  • 结果错了,只看 solve
  • 格式错了,只看 format_output
  • 主流程非常短,复盘时一眼就能看懂

一个通用的思考模板

写代码前,先回答下面四个问题:

  1. 输入里一共有几类数据,每类数据的类型是什么?
  2. 中间计算最关键的状态变量有哪些?
  3. 最终答案是一项结果,还是一组结果,还是排序后的列表?
  4. 输出是否需要额外解释、格式化、去重、保留顺序?

如果四个问题答不清,通常说明还没有真正读懂题。

模块边界应该如何设计

对计算类题目

s1-jh-01-heritage-costings3-jh-01-trade-conversion

  • 解析输入:规格、数量、损耗、税率、汇率
  • 核心计算:总价、折损、换算、累计
  • 格式输出:保留位数、按顺序打印

对数据清洗类题目

s1-jh-03-heritage-data-standard

  • 解析输入:原始记录
  • 清洗函数:补字段、纠格式、去无效项
  • 核心求解:统计、筛选、排序
  • 输出:标准化记录或汇总表

对流程模拟类题目

s1-jh-02-heritage-simulations2-jh-03-propagation-sim

  • 解析输入:初始状态、规则、事件序列
  • 单步更新函数:处理一次状态变化
  • 总流程函数:多轮模拟
  • 输出:最终状态、累计结果、告警次数

对规划调度类题目

s2-jh-01-route-supplys4-jh-02-production-plan

  • 解析输入:节点、边、约束、资源
  • 建模函数:构图、生成状态、构造候选方案
  • 求解函数:枚举、贪心、动态规划或搜索
  • 输出:最优值、路线、方案明细

复杂度意识要提前进入模块设计

如果模块边界设计得好,复杂度问题会更容易看见。

例如:

  • solve 每次都重新解析字符串,说明解析逻辑没有前置
  • 若排序前没有筛选,说明数据预处理模块缺失
  • 若每次状态更新都扫描整个数组,说明状态表示可能不合适

常见优化方向:

  • 先预处理,再进入主算法
  • 先筛选,再排序
  • 把重复计算结果缓存到变量或数组
  • 用字典或集合替代重复查找

输入输出分析的具体做法

可以为每道题先画一个简表:

项目要回答的问题
输入结构有几行、几列、几组数据
字段类型整数、浮点数、字符串、布尔量、编码串
约束条件范围、是否去重、是否有缺失值
中间状态需要维护哪些累计量、排名、状态变量
输出结构单值、列表、表格、排序结果、策略建议

这一步非常适合在纸面或 01-requirements 文档里先做,不必一上来就进编辑器。

常见错误与修正方式

错误 1:把输入提示语写进代码

现象:

  • 代码里有 print("请输入...")
  • 本地看起来正常,评测直接错误

修正:

  • 删除所有与题面无关的提示输出
  • 让程序只读标准输入、只写标准输出

错误 2:边解析边计算,最后逻辑缠在一起

现象:

  • 一个循环里既拆字符串,又更新状态,又打印结果
  • 稍微改一点规则就全盘牵动

修正:

  • 先完成解析,再完成求解,最后统一输出
  • 把复杂条件判断放进独立函数

错误 3:调试打印混进正式输出

现象:

  • 样例本地看得见过程,提交后格式错误

修正:

  • 用日志文件、注释掉的调试分支或标准错误记录
  • 提交前专门检查输出函数

错误 4:函数命名和职责不清

现象:

  • work()doit()calc2() 之类函数越来越多
  • 复盘时完全看不出每步在做什么

修正:

  • 用“动作 + 对象”的命名方式,如 parse_recordsupdate_statecompute_cost
  • 每个函数只做一件类型明确的事

训练建议

  1. 任选一道已有 case,先不写算法,只把输入和输出框架完整写出来。
  2. 再补 solve,并确保 main 里只有少量调用代码。
  3. 故意构造一组异常输入,观察是解析错、计算错,还是输出错。
  4. 用同一套模块骨架分别改写一题计算题和一题模拟题,体会结构的复用性。

自检清单

  • 是否只使用标准输入与标准输出
  • 是否没有额外提示语
  • 是否把解析、求解、输出拆开
  • 是否能只替换 solve 就复用其余框架
  • 是否对样例和边界数据都做过测试

与其他分区的联系

  • 与“算法基础”分区配合:算法基础告诉你“怎么算”,本页告诉你“怎么把它写对”。
  • 与“调试与优化”分区配合:本页先建立稳定骨架,后续调试才有清晰入口。
  • 与“题型模式”分区配合:不同题型会影响模块划分重点,但整体骨架保持一致。