枚举算法是我们在日常中使用到的最多的一个算法,本篇将会介绍枚举算法的思想与实例讲解,在使用频率上,枚举算法在蓝桥杯比赛里用的次数非常多,所以需要在平时多练习做题,毕竟实践检验真理,毕竟枚举在考试中出现的频率非常高,可谓是得枚举者得天下,下面我们就来讲讲枚举。
一、 枚举算法的思想
谈到枚举算法,所谓的枚举算法就是按问题本身的性质,一一列举出该问题所有可能的解,并在逐一列举的过程中,检验每个可能解是否是问题的真正解,若是,我们采纳这个解,否则抛弃它。在列举的过程中,既不能遗漏也不应重复。
(1)枚举算法的定义:
在进行归纳推理时,如果逐个考察了某类事件的所有可能情况,因而得出一般结论,那么该结论是可靠 的,这种归纳方法叫做枚举法。
(2)枚举算法的思想是:
将问题的所有可能的答案一一列举,然后根据条件判断此答案是否合适,保留合适的,舍弃不合适的。
(3)使用枚举算法解题的基本思路如下:
1. 确定枚举对象、范围和判定条件。
2. 逐一枚举可能的解并验证每个解是否是问题的解。
(4)枚举算法步骤:
1. 确定解题的可能范围,不能遗漏任何一个真正解,同时避免重复。
2. 判定是否是真正解的方法。
3. 为了提高解决问题的效率,使可能解的范围将至最小。
(5)枚举算法的流程图如下所示:
先判断值是否在范围内,然后判断是否符合条件,最后输出或者取下一个值,直到结束,下面通过例题来学习一下这种算法思想。
二、枚举算法的实例
以下是一个使用枚举解题与优化枚举范围的例子。
例题:
一个数组中的数互不相同,求其中和为0的数对的个数。
解题思路:
枚举两个数的代码很容易就可以写出来。
// C++ Version for (int i = 0; i < n; ++i) for (int j = 0; j < n; ++j) if (a[i] + a[j] == 0) ++ans;
# Python Version for i in range(0, n): for j in range(0, n): if(a[i] + a[j] == 0): ans = ans + 1
来看看枚举的范围如何优化。由于题中没要求数对是有序的,答案就是有序的情况的两倍(考虑如果 (a, b) 是答案,那么 (b, a) 也是答案)。对于这种情况,只需统计人为要求有顺序之后的答案,最后再乘上2就好了。
不妨要求第一个数要出现在靠前的位置。代码如下:
// C++ Version for (int i = 0; i < n; ++i) for (int j = 0; j < i; ++j) if (a[i] + a[j] == 0) ++ans;
# Python Version for i in range(0, n): for j in range(0, i): if(a[i] + a[j] == 0): ans = ans + 1
不难发现这里已经减少了j 的枚举范围,减少了这段代码的时间开销。
我们可以在此之上进一步优化。
两个数是否都一定要枚举出来呢?枚举其中一个数之后,题目的条件已经确定了其他的要素(另一个数)的条件,如果能找到一种方法直接判断题目要求的那个数是否存在,就可以省掉枚举后一个数的时间了。较为进阶地,在数据范围允许的情况下,我们可以使用桶记录遍历过的数。
// C++ Version bool met[MAXN * 2]; memset(met, 0, sizeof(met)); for (int i = 0; i < n; ++i) { if (met[MAXN - a[i]]) ans += 1; met[MAXN + a[i]] = true; }
# Python Versionmet = [False] * MAXN * 2for i in range(0, n): if met[MAXN - a[i]]: ans = ans + 1 met[a[i] + MAXN] = True
C语言网提供由在职研发工程师或ACM蓝桥杯竞赛优秀选手录制的视频教程,并配有习题和答疑,点击了解:
一点编程也不会写的:零基础C语言学练课程
解决困扰你多年的C语言疑难杂症特性的C语言进阶课程
从零到写出一个爬虫的Python编程课程
只会语法写不出代码?手把手带你写100个编程真题的编程百练课程
信息学奥赛或C++选手的 必学C++课程
蓝桥杯ACM、信息学奥赛的必学课程:算法竞赛课入门课程
手把手讲解近五年真题的蓝桥杯辅导课程