PrevNext
Resources
KACTL

ICPC 比赛中可以尝试的排错方法

Errichto

本模块以上述资源为基础,并选取了与 USACO 最相关的内容。

代码片段

本模块不包含代码。更多信息参见基础调试C++ 调试

提交前

  • 代码应当具有可读性,至少要让你自己能够读懂。
    • 可以参考添加题解模块中的代码 风格建议。

答案错误(或运行错误)

  • 输出格式是否正确?

    • 提交前是否删除了调试输出?
  • 是否处理了所有边界情况(例如 N=1N=1)和特殊情况?

  • 对含有多组独立测试数据的题目(例如此题), 是否在每组数据之间清空了所有数据结构?

    • 有时程序只会在较大的测试数据之后紧跟较小数据时出错。
  • 是否正确理解了题意?重新完整阅读一遍题面。

  • 再读一遍代码。

    • 是否混淆了 NNMMiijj 等变量?
  • 是否存在被遮蔽、未使用或 未初始化的变量?

    • C++ 使用警告选项 -Wall -Wshadow 编译时通常能发现这些问题。
  • 是否存在_未定义行为_?它可能导致本地与在线评测结果不同,例如样例在本地 通过,提交到 USACO 却失败。尝试在多个环境中运行代码,例如 USACO Guide IDECodeforces 自定义测试, 观察结果是否始终相同。常见的未定义行为包括:

    • C++:未初始化的变量;

    • C++:非 void 函数没有返回值;

    • C++:数组越界;

      • 可以按此处所述使用 ::at
    • C++ / Java: 有符号整数溢出

      • 若题目需要 64 位而非 32 位整数,USACO 通常会给出类似下面的提示,但很 容易被忽略:

      请注意,本题涉及的整数较大,可能需要使用 64 位整数类型(例如 C/C++ 中的 long long)。

    • C++:将一个 32 位整数移位 32\ge 32 位。

    C++ 使用检测选项 -fsanitize=address,undefined 编译,有助于发现这些问题。

  • 添加断言后重新提交。

  • 浮点数:

    • 是否产生了 NaN,例如对负数开平方?
    • 尝试使用精度更高的类型,例如 C++ 中用 long double 代替 double
    • 输出精度是否正确?
  • 算法本身是否真的正确?

    • 用简单样例手动执行算法,或编写测试数据运行。
    • 编写数据生成器,把程序输出与较简单的暴力解或标准解比较。

运行错误

  • 是否存在未定义行为(见上文)?
  • 是否有可能失败的断言?
  • 是否可能除以零,例如对零取模?
  • 是否可能无限递归?
  • 是否使用了已经失效的指针或迭代器?
  • 是否占用了过多内存?

超出时间限制

  • 是否可能存在死循环?
  • 算法复杂度是多少?
  • 提交前是否移除了调试输出,例如是否向标准错误流 输出了大量信息?
  • 是否进行了不必要的数据复制?C++ 中可考虑按引用传参。
  • C++ 中尝试用 array 替代 vector

最后的办法

  • 从头重写解答。
    • 务必保留原代码的副本,因为新实现也可能引入更多错误。

USACO Guide Forum 发帖前

  • 如果已经找到程序失败的小测试,并且知道正确输出为何成立,通常应当能自行 找出程序错误。
    • 在代码中添加输出语句,与手动模拟的结果逐步比较。
    • 按上文说明检查未定义行为。
  • 如果还没有找到失败的小测试:
    • 尝试下载官方测试数据,查看程序是否在其中的小数据上失败。
    • 若仍不行,按上文方法生成一个能使程序失败的小测试。

Module Progress:

PrevNext