第 14 章 排列組合與機率¶
(適用:台灣高中~大一;目標:用 SageMath 做「計數驗算、列舉、生成函數初步、機率計算與模擬」)
14.1 本章主旨:把「計數」變成可驗算的流程¶
排列組合與機率的常見困難:
- 題目敘述一長串,容易漏條件或重複計數
- 公式背得住,但不知道何時用
- 機率算完不確定合理不合理
SageMath 可以做三種支援:
- 符號計數:排列、組合、二項式係數
- 列舉驗算:小規模暴力列出所有情況,檢查你是否漏算/重算
- 模擬(Monte Carlo):用大量隨機試驗估計機率,檢查答案是否合理
建議工作流:先手算 → 用列舉/模擬驗算 → 再回頭修正推理。
14.2 基本計數工具:階乘、排列、組合¶
Sage 常用:
factorial(n)或n.factorial()binomial(n,k)(組合數)- 排列數 $$ P(n,k)=\frac{n!}{(n-k)!} $$ 可以自己寫函數
先做幾個例子。
In [1]:
# 階乘與組合
factorial(6), binomial(10, 3)
Out[1]:
In [ ]:
def P(n, k):
return factorial(n)/factorial(n-k)
P(10, 3)
In [3]:
var('x')
expr = expand((x+1)^8)
expr
Out[3]:
In [4]:
# 取出 x^k 的係數(例如 k=3)
expr.coefficient(x, 3), binomial(8, 3)
Out[4]:
In [5]:
# AABBC 的排列數
factorial(5)/(factorial(2)*factorial(2))
Out[5]:
列舉驗算(小規模暴力)¶
用 Python 的 itertools 列出所有排列(注意:數量大會爆!只適合小問題)。
In [6]:
import itertools
letters = ['A','A','B','B','C']
perms = set(itertools.permutations(letters))
len(perms), list(perms)[:5]
Out[6]:
In [7]:
binomial(12, 5)
Out[7]:
In [8]:
binomial(3+7-1, 7)
Out[8]:
In [9]:
2^5 - 1
Out[9]:
In [10]:
pairs = [(a, 10-a) for a in range(1, 10)]
pairs, len(pairs)
Out[10]:
In [11]:
outcomes = [(i,j) for i in range(1,7) for j in range(1,7)]
A = [(i,j) for (i,j) in outcomes if i+j == 7]
len(outcomes), len(A), len(A)/len(outcomes), A
Out[11]:
例 2:至少一顆是 6 的機率(用補集更快)¶
In [12]:
# 補集:沒有任何 6
no6 = [(i,j) for (i,j) in outcomes if i != 6 and j != 6]
1 - len(no6)/len(outcomes)
Out[12]:
14.8 超幾何分佈:不放回抽樣(高中到大一都常出)¶
例:盒子有 5 個紅球、7 個藍球,不放回抽 3 顆,剛好抽到 2 紅 1 藍的機率?
$$ P=\frac{\binom{5}{2}\binom{7}{1}}{\binom{12}{3}} $$
In [13]:
P_exact = binomial(5,2)*binomial(7,1)/binomial(12,3)
P_exact, N(P_exact)
Out[13]:
用模擬驗算(Monte Carlo)¶
大量隨機抽樣,估計機率(應該接近上面結果)。
In [14]:
import random
def trial():
balls = ['R']*5 + ['B']*7
sample = random.sample(balls, 3) # 不放回抽 3
return sample.count('R') == 2 and sample.count('B') == 1
N = 20000
est = sum(trial() for _ in range(N))/N
est
Out[14]:
In [15]:
reset() # 清除之前的變數
P = binomial(10,3)*(1/2)^10
P, N(P)
Out[15]:
用模擬驗算¶
In [16]:
import random
def coin_trial(n=10):
heads = sum(1 for _ in range(n) if random.random() < 0.5)
return heads == 3
N = 30000
est = sum(coin_trial() for _ in range(N))/N
est
Out[16]:
In [17]:
# 骰子期望
E = sum(k*(1/6) for k in range(1,7))
E
Out[17]:
也可以用模擬估計期望:
In [18]:
import random
N = 50000
est = sum(random.randint(1,6) for _ in range(N))/N
est
Out[18]:
14.11 本章小結:計數與機率的可靠工作流¶
你現在應該能:
- 用
factorial、binomial做基本排列組合計算 - 用列舉(itertools)驗算小規模計數題
- 用補集、分情況等策略組織推理
- 用組合數寫出古典機率(骰子/抽球/硬幣)
- 用 Monte Carlo 模擬檢查你的機率答案是否合理
- 初步理解期望值是「加權平均」並能用模擬驗算
練習題(附提示)¶
計數:字母 A A A B B C 的不同排列有多少?
提示:$\frac{6!}{3!2!}$,也可用 set(permutations) 小規模驗算。補集:長度 8 的二進位字串中,至少有一個 0 的個數?
提示:總數 2^8 減掉全 1。抽球(超幾何):箱中 4 白 6 黑,不放回抽 5 顆,抽到恰好 3 白的機率。
提示:$\binom{4}{3}\binom{6}{2}/\binom{10}{5}$。二項:某題命中率 0.3,做 8 次,恰好命中 2 次的機率。
提示:$\binom{8}{2}0.3^2 0.7^6$。
5.(挑戰)條件機率:兩顆骰子,已知至少一顆是 6,求和為 7 的機率。
提示:用列舉:B=「至少一顆 6」,A=「和為 7」,算 |A∩B|/|B|。
下一章(第 15 章)我們會進入「資料分析:平均數、變異數與標準差」:
會把「期望」的概念延伸到資料,並用 Sage/Python 做統計量計算與視覺化。