要学习的知识点
- 枚举数位组合
- 三位数的百位限制
- 偶数末位
- 加法原理与乘法原理
- 用程序验证计数
题目
练习 17:枚举 0~9 中不重复数字组成的三位偶数,并用乘法原理验证。
完整代码
以下内容与 ex17.py 一致,可对照右侧讲解阅读。
"""练习 17:枚举 0~9 中不重复数字组成的三位偶数,并用乘法原理验证。
学习说明:
- 三重循环分别选择百位、十位、个位;百位从 1 开始,保证数是三位数。
- 偶数的个位只能是 0、2、4、6、8;三个位置还必须互不相同。
- 乘法原理计算时分个位为 0 和个位非 0 两种情况,避免把可选数字数错。
- 两种独立方法都求出数量,最后输出以便核对。
"""
count_by_enumeration = 0
# 逐一枚举三个数位的所有候选组合。
for hundreds in range(1, 10):
for tens in range(10):
for ones in (0, 2, 4, 6, 8):
if hundreds != tens and hundreds != ones and tens != ones:
count_by_enumeration += 1
# 个位为 0:9 种百位 × 8 种十位。
# 个位为 2、4、6、8:4 × 8 种百位 × 8 种十位。
count_by_rule = 9 * 8 + 4 * 8 * 8
print("enumeration:", count_by_enumeration)
print("counting principle:", count_by_rule)
进阶写法
这版与初学版解决同一道题,使用更精炼的语法或标准库工具。
进阶源码:ex17_adv.py
"""练习 17 进阶版:用 itertools.permutations 枚举不重复数位。"""
from itertools import permutations
digits = "0123456789"
valid_numbers = (
number for number in permutations(digits, 3)
if number[0] != "0" and number[2] in "02468"
)
enumeration_count = sum(1 for _ in valid_numbers)
counting_principle_count = 9 * 8 + 4 * 8 * 8
print("enumeration:", enumeration_count)
print("counting principle:", counting_principle_count)
permutations() 生成不重复数位排列;过滤百位 0 和奇数个位后用 sum() 计数。公式部分仍按个位是否为 0 分类。
运行结果
示例输入:
(本题程序不需要输入)程序输出:
enumeration: 328
counting principle: 328逐个认识函数
下表根据程序中实际调用的函数和方法整理;自定义函数的实现与算法细节见后续说明。
| 函数形式 | 功能与返回值 | 注意事项 |
|---|---|---|
print(*objects, sep=' ', end='\n') | 把对象转换为文本显示;返回 None。 | 默认空格分隔并在末尾换行。 |
range(start, stop, step=1) | 产生整数序列供循环或索引使用。 | stop 不包含在序列里。 |
先把情况分开
个位为偶数,有两类情况:
- 个位是 0:百位可选 1–9,共 9 种;十位不能与百位重复,也不能为 0(因为 0 已在个位),剩 8 种。合计 9×8=72。
- 个位是 2、4、6、8:个位有 4 种。固定个位后,百位可从 1–9 中选,排除个位,剩 8 种;十位从 0–9 中选,排除已用的百位和个位,剩 8 种。合计 4×8×8=256。
- 两类互斥,合计 72+256=328。
这是加法原理和乘法原理的配合:同一类的连续步骤相乘,不同且互斥的类别相加。
程序中的语法与内置函数
| 写法 | 参数 / 返回值 | 作用 |
|---|---|---|
range(start, stop) | 生成 start 到 stop-1 的整数序列。 | hundreds 从 1 到 9,确保三位数;tens 从 0 到 9。 |
(0, 2, 4, 6, 8) | 元组字面量,可直接遍历。 | 限定 ones 只能取偶数个位。 |
and | 逻辑运算符,不是函数;两边条件都真时结果为 True。 | 检查三个数位两两不同。 |
+= | 累加赋值,等价于左边变量加右边值再保存。 | 每找到一种组合,将总数加 1。 |
print(...) | 输出对象,返回 None。 | 同时展示枚举结果和公式结果用于交叉验证。 |
枚举为何可信
三层循环遍历百位、十位、个位所有合法范围;条件确保无重复。每种满足条件的数恰好经过一次,因此统计值准确。公式计数则把可能性按个位分类,避免逐个列出。两种方法结果相同,是很好的检查方式。
数位的“位置”很重要:数字 0 可以出现在十位或个位,但不能出现在百位。计数时不能把每个位置都简单当成 10 种。
代码如何运行
- 先按左侧题目给出的格式输入数据;程序通过 input() 读取,并在需要时转换数据类型。
- 程序自上而下执行语句;遇到条件、循环或函数调用时,按照右侧算法说明更新变量和处理数据。
- 最后由 print() 输出计算结果。可将左侧示例输入与输出逐项对照。
先自己跟踪一组小数据,记录循环前后变量的值;这比只看最终答案更容易理解程序。
自己动手试一试
将三位偶数改为三位奇数,重新分类个位情况,再用枚举结果验证公式。
先在 lx17.py 中独立完成,再运行参考程序比较结果。修改程序时一次只改一个条件或步骤。