枚举题的核心:把“所有可能”变成“有序检查”
枚举是编程竞赛中基础且常见的题型。它不要求高深算法,但要求穷尽所有可能情况,并保证不遗漏、不重复。很多人卡在入门题上,往往不是不会写代码,而是枚举时思路混乱,要么漏掉边界,要么把同一情况算了多遍。解决的办法不是“更仔细”,而是先建立一套固定的枚举框架。
明确枚举对象与范围
拿到题目先问:要枚举的是什么?是数组下标、坐标点、还是元素组合?例如“从1到5中选两个不同的数,使它们的和为6”,枚举对象就是所有无序数对。范围要覆盖所有合法情况,同时排除明显不可能的项。范围设计得越清楚,后续去重就越简单。
用循环范围控制去重:一个自拟例子
假设题目是:从1到5中选两个不同的数,使它们的和为6,输出所有可能的无序数对。如果用两层循环,外层i从1到5,内层j也从1到5,那么(1,5)和(5,1)都会被输出,这就是重复;如果允许i等于j,还会出现(3,3)这种不满足要求的数对。
可以让内层循环从i+1开始:外层i从1到4,内层j从i+1到5。这样j始终大于i,所以(1,5)和(5,1)不会同时出现,i等于j的情况也不可能发生。检查这些数对,和为6的只有(1,5)和(2,4)。这个例子说明,循环范围本身就能承担去重任务,不需要事后判断。
组合与路径类问题的去重思路
对于组合类问题,可以规定“按固定顺序选取”。比如枚举一个数组的所有组合时,规定按下标从小到大选取,这样同一组下标只有一种表示,不会重复。如果枚举不重复经过格子的路径,可记录当前路径已访问的格子,进入分支时标记、回溯时撤销;如果问题允许重复经过,或只问可达性,状态设计则不同,不能一律使用永久访问标记。去重规则越早设计,代码通常越简单;等到输出时再判断,往往已经晚了。
检查遗漏:边界与极端情况
不遗漏比不重复更难。常见遗漏点有三个:一是边界值,例如循环范围是1到n时,要确认n本身被覆盖;二是空集或零值,例如枚举组合时是否包含空集;三是极端输入,例如n=1或n=2时,循环是否还能正确执行。
建议在写完枚举代码后,手动模拟几个小规模输入。比如枚举从1到n中选两个数的所有组合时,先手写n=3的全部组合,再与程序输出对比。如果题目要求输出所有解,可以在代码里加一个计数器,最后核对计数是否与手算一致。这是实用的自检方法,不是官方要求。
总结
枚举题的本质是“有序地穷举”。明确枚举对象、范围与去重依据后,还需要说明每个合法解为何都会被枚举到,以及为何不会被重复表示。这套方法适用于大多数入门级枚举题,也是后续学习搜索和动态规划的基础。



