排列与组合
困难2排列与组合:从排队选座位到分组打扫卫生
排列和组合是数学中帮我们“数一数有多少种方法”的工具。生活中到处需要数方法:比如从班级里选几个人排成一排拍照,或者选几个人去参加活动,方法数不一样。排列讲顺序,顺序不同就算不同;组合不讲顺序,只关心选了哪些人。学好它们,你就能轻松算出抽奖中奖概率、游戏里的搭配方案等。
什么是排列?—— 排队选座位,顺序很重要
定义:从 个不同元素中取出 个(),按一定顺序排成一列,叫做一个排列。顺序不同就是不同的排列。
生活例子:从A、B、C三个同学中选两个排座位(比如第一排和第二排)。
- 可能的排法:AB(A第一,B第二)、BA(B第一,A第二)、AC、CA、BC、CB,一共6种。
- 注意:AB和BA虽然选的人一样,但座位不同,所以算两种。
公式:
其中 表示从1乘到n的阶乘,例如 。
算出 ,和例子吻合。
什么是组合?—— 选人参加活动,只看有谁
定义:从 个不同元素中取出 个(),不计顺序,只考虑选出了哪些人,叫做一个组合。
生活例子:从A、B、C中选两个人去扫地。
- 可能的组合:AB、AC、BC,只有3种。
- 为什么?因为AB和BA是同一组人,扫地的活不分谁先谁后,所以只算一次。
公式:
算出 ,和例子吻合。
如何用Python快速计算?
Python的 math 模块已经帮我们准备好了两个函数:perm 计算排列数,comb 计算组合数。你也可以自己写函数实现,方便理解原理。
方法一:直接用 math 模块(推荐)
import math
# 排列:从5个元素中取3个排列
print(math.perm(5, 3)) # 输出60
# 组合:从5个元素中取3个组合
print(math.comb(5, 3)) # 输出10
方法二:自己写阶乘函数
def factorial(n):
result = 1 # 初始化结果为1
for i in range(2, n + 1): # 从2乘到n
result *= i
return result
def perm(n, m):
return factorial(n) // factorial(n - m)
def comb(n, m):
return factorial(n) // (factorial(m) * factorial(n - m))
print(perm(5, 3)) # 输出60
print(comb(5, 3)) # 输出10
注意:// 是整数除法,因为阶乘结果一定是整数,所以直接用整除不会出错。
常见错误与注意事项
-
混淆排列和组合
- 题中说“排队”、“照相”、“名次”等有顺序的,用排列。
- 题中说“选几个人”、“分组”、“参加活动”等不考虑顺序的,用组合。
- 练习:从5个同学中选3个参加跳绳比赛,是组合;选3个分别担任班长、学习委员、体育委员,是排列。
-
当 时
- 什么都不选,只有一种情况:就是“一个都不选”。所以排列数和组合数都是1。
- 例如
math.perm(5, 0)返回 1,math.comb(5, 0)也返回 1。
-
当 时
- 不可能从5个元素中取6个,结果就是0。
math.perm(5, 6)和math.comb(5, 6)都返回 0。
- 不可能从5个元素中取6个,结果就是0。
-
阶乘计算要小心大数
- Python 的整数可以无限大,所以直接用
math.perm或自己写阶乘都没问题。但在某些语言里,大数会溢出,Python 不用怕。
- Python 的整数可以无限大,所以直接用
-
公式中的除法要保证整除
- 公式看起来有除法,但结果一定是整数。自己写时记得用
//整除,避免出现浮点数。
- 公式看起来有除法,但结果一定是整数。自己写时记得用
完整示例:班级选班长分组程序
下面是一个完整的程序,让用户输入总人数、要选的人数,然后选择计算排列还是组合,输出结果并附带生活解释。
import math
# 获取用户输入
n = int(input("请输入总人数(n): ")) # 总人数
m = int(input("请输入选取人数(m): ")) # 选取人数
if m > n:
print("错误:选取人数不能大于总人数!")
else:
# 选择计算类型
choice = input("计算排列请输入P,计算组合请输入C: ").upper()
if choice == 'P':
result = math.perm(n, m)
print(f"从{n}人中选{m}人排成一排,有{result}种方法。")
print("解释:排队顺序很重要,比如AB和BA算两种。")
elif choice == 'C':
result = math.comb(n, m)
print(f"从{n}人中选{m}人参加活动,有{result}种方法。")
print("解释:只关心选哪些人,不关心顺序,比如AB和BA算一种。")
else:
print("请输入P或C!")
运行示例:
请输入总人数(n): 5
请输入选取人数(m): 3
计算排列请输入P,计算组合请输入C: P
从5人中选3人排成一排,有60种方法。
解释:排队顺序很重要,比如AB和BA算两种。
相关知识点延伸
排列与组合是概率论的基础:比如从10张奖券中抽一张中奖的概率就是 ,但如果抽两张且不考虑顺序,中奖组合数就用组合算。
在编程竞赛中,很多计数问题(比如用动态规划求方案数)本质上就是排列组合的变形。
如果你对阶乘的快速计算感兴趣,可以学习乘法原理和递归;对组合数取模的问题(比如结果很大,只要求输出对某个数取余),则要学会模逆运算和卢卡斯定理。
下一步建议学习:概率初步、二项式定理( 的展开系数就是组合数)、容斥原理(既会排列又会组合才能解决更复杂的问题)。
例题精讲
从5本不同的书中选3本送给3位同学,每人一本,有多少种不同的送法?
从6名同学中选出3人参加志愿者活动,不考虑顺序,共有C(6,3)=20种选法。
以下函数用于计算组合数C(n,m),请补全代码。
def comb(n, m):
if m < 0 or m > n:
return 0
if m == 0 or m == n:
return 1
return comb(n-1, m-1) + ___用数字0,1,2,3组成没有重复数字的三位数,共有多少个?
以下代码使用Python的itertools模块生成所有排列,请补全输出排列个数的语句。
import itertools
items = ['A','B','C']
perms = list(itertools.permutations(items, 2))
print(___)
# 应输出6,但要求输出排列个数