CC++ & Algorithm

枚举法 - 像侦探一样逐个检查

中等0
语言版本:C++
概述:枚举法就是按顺序把所有可能的情况都试一遍,找到正确答案,就像侦探挨个问嫌疑人一样简单。

枚举法 —— 像侦探一样逐个检查,简单又可靠

小朋友们,你们玩过“猜数字”游戏吗?一个人心里想一个 1 到 10 的数字,另一个人猜,但只能通过问“是还是不是”来找答案。最笨但最可靠的方法就是从 1 问到 10,每个数字都试试——这其实就是 枚举法 的灵魂。

枚举法(也叫穷举法)就是 把所有可能的情况一个一个列出来,检查每个情况是不是满足要求。就像你丢了一枚硬币,你想在房间里找到它,你就从床头柜开始,一格一格地翻,直到找到为止。虽然有点慢,但一定不会漏掉。

在编程里,我们经常用循环语句(比如 forwhile)来帮我们“挨个检查”。下面我们一步步拆解枚举法的用法,并看看它能在哪些地方帮我们解决问题。


一、枚举法是什么?—— 从“猜数字”到“找零钱”

枚举法听起来很高级,其实就是 把所有可能性列出来,一个一个试。比如:

  • 你想知道班级里谁最高,就挨个同学量身高,比一比。
  • 妈妈让你猜她买了几个苹果,你说“1个?2个?3个?……”直到猜对。
  • 你有一把锁,忘了密码是 1234 还是 4321,那就两个都试一遍。

这些例子都用到枚举法。在编程中,我们用 循环 来替我们做“挨个检查”的苦力活,用 条件判断 来筛选出满足要求的结果。


二、枚举法的核心步骤:循环 + 条件判断

枚举法在代码中一般由两部分组成:

  1. 循环 —— 用来遍历所有可能的值(比如从 1 到 100)。
  2. 条件判断 —— 对每个值检查是否符合题目要求。

比如下面这段代码,找出 1 到 20 中所有的偶数:

# 枚举法:找出1到20中所有的偶数
print("1到20中的偶数有:")
for number in range(1, 21):   # 从1到20逐个枚举
    if number % 2 == 0:       # 检查这个数是不是偶数
        print(number, end=" ")
# 输出:2 4 6 8 10 12 14 16 18 20

你看,程序从 1 数到 20,每个数都问一遍“你除以 2 有没有余数?”如果没有余数,就说明它是偶数,我们就把它记下来。


三、生活中的枚举法例子

例子 1:统计班里身高超过 150 厘米的同学

假设我们有一个列表 heights 记录了全班 40 个同学的身高(单位:厘米)。我们要找出所有身高超过 150 厘米的同学。

# 枚举法:统计身高超过150厘米的同学
heights = [145, 152, 160, 138, 149, 155, 148, 162, 140, 158]  # 假设只有10个同学
print("身高超过150厘米的同学:")
for h in heights:                # 枚举每个同学的身高
    if h > 150:                  # 检查是否超过150
        print(h, end=" ")        # 输出符合条件的值
# 输出:152 160 155 162 158

例子 2:找零钱组合

小明有 1 元、2 元、5 元的硬币各若干枚,他想凑出 10 元,可以怎么组合?枚举法可以列出所有可能的硬币数量搭配。

# 枚举法:找零钱组合凑出10元
print("能凑出10元的组合(1元、2元、5元):")
for one in range(0, 11):           # 枚举1元硬币的数量(最多10个)
    for two in range(0, 6):        # 枚举2元硬币的数量(最多5个)
        for five in range(0, 3):   # 枚举5元硬币的数量(最多2个)
            if 1*one + 2*two + 5*five == 10:  # 检查总金额是否为10
                print(f"1元×{one} + 2元×{two} + 5元×{five}")

这个例子用了三重循环,虽然看起来很慢,但对于这种小数据量完全没问题。


四、新手容易犯的错误

  1. 范围设置错误
    比如要枚举 1 到 10,却写成 range(1, 10),这样只会到 9。记得 Python 中 range(start, stop) 不包含 stop 本身。
    ✅ 正确:range(1, 11)range(1, 21)(到 20)。

  2. 忘记初始化变量或输出语句放错位置
    有时我们需要在循环外面定义一个变量(比如计数器),如果写在循环里面,每次循环都被重置。
    ❌ 错误:

    count = 0
    for i in range(1, 11):
        if i % 2 == 0:
            count = count + 1   # 如果这句写在循环外,但变量定义放错了位置……
    

    正确写法:变量在循环前定义好。

  3. 枚举范围太大导致程序卡死
    比如要枚举 1 到 1 亿,电脑会算很久,甚至内存溢出。所以枚举法适合数据量小的题目(通常不超过几百万次循环)。如果题目数据很大,需要想办法缩小范围。

  4. 条件判断写反
    比如想找偶数却用了 number % 2 != 0,结果找了一堆奇数。注意仔细审题。


五、完整示例:鸡兔同笼问题

鸡兔同笼,头共 35 个,脚共 94 只,问鸡和兔各有多少只?

枚举法:假设鸡有 chicken 只,兔有 rabbit 只,那么:

  • 头数:chicken + rabbit == 35
  • 脚数:2 * chicken + 4 * rabbit == 94

我们用循环枚举鸡的只数(0 到 35),然后算出兔的只数,再检查脚数是否匹配。

# 枚举法解决鸡兔同笼问题
head = 35            # 总头数
foot = 94            # 总脚数
found = False        # 是否找到答案

for chicken in range(0, head + 1):   # 枚举鸡的只数(0到35)
    rabbit = head - chicken           # 兔的只数 = 总头数 - 鸡的只数
    if 2 * chicken + 4 * rabbit == foot:   # 检查脚数是否匹配
        print(f"鸡有 {chicken} 只,兔有 {rabbit} 只")
        found = True
        break                            # 找到一组解就退出循环(题目通常只有一组解)

if not found:
    print("没有找到符合要求的解。")

输出:

鸡有 23 只,兔有 12 只

这段代码完整可运行。注意我们用了一个布尔变量 found 来记录是否找到解,找到了就 break 提前停止循环,避免浪费时间继续检查。


六、如何让枚举法更高效?—— 学会“聪明地枚举”

虽然枚举法很暴力,但我们可以让电脑少干点活:

  • 缩小枚举范围:比如找两个数加起来等于 10,第一个数从 1 到 10 枚举就够了,第二个数可以直接用 10 减去第一个数,不用再枚举第二个数。
  • 利用数学性质剪枝:比如判断质数,只要试到平方根就够了。
  • 改循环为更快的算法:如果数据量太大,枚举会超时,需要换其他方法(比如二分查找、动态规划等)。

七、相关知识点指引

学会了枚举法,你还可以继续了解:

  • 循环结构forwhile 的用法(尤其是 range 的多种写法)
  • 条件判断if-elif-else 的嵌套
  • 列表与字符串:枚举列表中的元素、字符串中的字符
  • 算法复杂度:为什么枚举法有时很慢,以及如何估算循环次数
  • 搜索剪枝:在枚举过程中提前排除不可能的情况(例如在“找零钱”例子中,如果当前硬币已经超过目标金额,提前停止内层循环)

枚举法就像你的侦探助手,虽然有时慢了一点,但从不撒谎。掌握它,你就能轻松解决许多编程入门题!

例题精讲

1单选题

以下哪个问题最适合使用枚举法解决?

A查找有序数组中的最大值
B判断一个数是否为质数
C从1到100中找出所有能被3整除的数
D计算斐波那契数列的第n项
2判断题

枚举法一定能保证找到最优解,但效率可能较低。

3填空题
用枚举法求1到100中所有偶数的和,补全代码:
sum = 0
for i in range(1, 101):
    if ___:
        sum += i
print(sum)