二项式定理与杨辉三角
困难4从买零食到多项式:二项式定理和杨辉三角的编程之旅
你有没有发现,当我们计算 (a+b)² 和 (a+b)³ 的时候,系数好像藏着某种规律?
1, 2, 1 → 1, 3, 3, 1 → 1, 4, 6, 4, 1 → ……
这些数字排成一个三角形,叫做杨辉三角(西方叫帕斯卡三角形)。它不但漂亮,还和组合数、二项式定理紧紧相连。学会它,你不仅能快速展开 (a+b)ⁿ,还能在编程中轻松计算组合数,甚至估算 (1.01)^100 这种大幂。
本文就带你从口诀一样的三角形出发,一步步理解二项式定理,并用 C++ 和 Python 把它写进代码里。
1. 从多项式展开中发现的三角形
先回忆一下:
- (a+b)² = a² + 2ab + b² → 系数:1, 2, 1
- (a+b)³ = a³ + 3a²b + 3ab² + b³ → 系数:1, 3, 3, 1
- (a+b)⁴ = a⁴ + 4a³b + 6a²b² + 4ab³ + b⁴ → 系数:1, 4, 6, 4, 1
把这些系数按行排成三角形:
第0行: 1
第1行: 1 1
第2行: 1 2 1
第3行: 1 3 3 1
第4行: 1 4 6 4 1
第5行: 1 5 10 10 5 1
这就是杨辉三角。每一行对应 (a+b)ⁿ 的展开系数,第 n 行第 k 个数(从 0 开始数)就是组合数 C(n, k)(读作“n 选 k”)。
生活中的例子:
你要从 5 个不同口味的棒棒糖里选 2 个,有多少种选法?答案就是 C(5,2) = 10 种。而杨辉三角第 5 行第 2 个数正是 10。
2. 二项式定理:一句话说出所有系数
二项式定理告诉我们:对于任何正整数 n,
其中 就是组合数 C(n, k)。
它的含义很简单:展开 (a+b)ⁿ 相当于从 n 个括号里,每次选一个出来取 a 或 b。想要得到 a^{n-k} b^k 这一项,就必须从 n 个括号中选出 k 个取 b,剩下的 n-k 个取 a。不同的选法个数正好是 C(n, k)。
思考题:
如果你和 4 个朋友一起玩抛硬币游戏,每人抛一次,想知道恰好出现 2 次正面、3 次反面的概率,就和 C(5,2) 有关。因为 5 次抛掷选择 2 次为正面的方案数就是 C(5,2) = 10。
3. 杨辉三角的构造规则(加法递推)
杨辉三角最神奇的地方在于:除了两边的 1,中间每个数都等于它上方两个数之和。
例如第 4 行中间的 6,等于第 3 行的 3 + 3;再比如第 5 行的 10,等于第 4 行的 4 + 6。
- 首尾固定为 1。
- 第 i 行第 j 个数(j 从 0 到 i)可由公式得到:
tri[i][j] = tri[i-1][j-1] + tri[i-1][j]
这个加法规则跟组合数的递推公式 C(n,k) = C(n-1, k-1) + C(n-1, k) 完全一样,因此杨辉三角就是组合数的“加法表”。
生活中的类比:
你每天零花钱的算法:今天零花钱 = 昨天剩下的钱 + 今天新发的钱。杨辉三角的每个数也是“上面两个钱数加起来”。
4. 新手容易犯的错误
❌ 错误1:混淆行和列的下标从0还是从1开始
- 杨辉三角的第 0 行只有一个数 1。
- 第 n 行有 n+1 个数,第 0 列和最后一列都是 1。
- 写代码时,如果循环从 1 开始,容易漏掉边界,导致数组越界。
正确做法:
第 i 行数组大小应为 i+1,循环 j 从 0 到 i,首尾单独赋 1,中间用递推。
❌ 错误2:递推时忘记更新上一行的数据
如果用二维数组,递推时要用 triangle[i-1][j-1] 和 triangle[i-1][j]。如果误写成 triangle[i][j-1] 或 triangle[i-1][j-1] 但当前行还没赋值,就会拿错值。
❌ 错误3:计算组合数时直接算阶乘溢出
直接写 n! / (k! * (n-k)!) 在 n=20 时就会非常大,导致整数溢出。用杨辉三角递推或帕斯卡恒等式可以避免大数阶乘。
5. 编程实现:生成杨辉三角并计算二项式系数
下面给出完整可运行的 C++ 和 Python 代码。
代码中变量名都用简短英文单词,并且每条变量定义都加了中文注释,方便你理解。
? C++ 实现(完整版)
#include <iostream>
#include <vector>
using namespace std;
/**
* 生成杨辉三角的前 n 行(第0行到第n行)
* @param n 最大行号(非负整数)
* @return 一个二维vector,每行是一个vector<long long>
*/
vector<vector<long long>> generateYangHui(int n) {
// triangle: 存储整个三角形,共有n+1行
vector<vector<long long>> triangle(n + 1);
for (int i = 0; i <= n; i++) {
// 第 i 行有 i+1 个数,先分配空间
triangle[i].resize(i + 1);
// 首尾都是 1
triangle[i][0] = 1;
triangle[i][i] = 1;
// 中间元素通过递推计算
for (int j = 1; j < i; j++) {
// 上一行的第 j-1 列 + 上一行的第 j 列
triangle[i][j] = triangle[i-1][j-1] + triangle[i-1][j];
}
}
return triangle;
}
/**
* 打印 (a+b)^n 的展开式(仅显示系数与项)
* @param n 指数
*/
void printBinomialExpansion(int n) {
// 先获取杨辉三角第 n 行
auto triangle = generateYangHui(n);
auto row = triangle[n]; // 第 n 行的系数列表
cout << "(a+b)^" << n << " = ";
for (int k = 0; k <= n; k++) {
long long coef = row[k]; // 系数 C(n,k)
// 输出项:coef * a^(n-k) * b^k
cout << coef;
if (n - k > 0) cout << "*a";
if (n - k > 1) cout << "^" << n - k;
if (k > 0) cout << "*b";
if (k > 1) cout << "^" << k;
if (k < n) cout << " + ";
}
cout << endl;
}
int main() {
int n;
cout << "请输入杨辉三角的行数(从0开始): ";
cin >> n;
auto tri = generateYangHui(n);
// 打印整个三角形
cout << "\n杨辉三角(第0行到第"<< n <<"行):\n";
for (int i = 0; i <= n; i++) {
for (int j = 0; j <= i; j++) {
cout << tri[i][j] << " ";
}
cout << endl;
}
// 单独打印第 5 行
if (n >= 5) {
cout << "\n第5行: ";
for (int j = 0; j <= 5; j++) {
cout << tri[5][j] << " ";
}
cout << endl;
}
// 打印 (a+b)^n 的展开式
cout << "\n展开式:\n";
printBinomialExpansion(n);
return 0;
}
运行示例(输入 5):
请输入杨辉三角的行数(从0开始): 5
杨辉三角(第0行到第5行):
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
第5行: 1 5 10 10 5 1
展开式:
(a+b)^5 = 1*a^5 + 5*a^4*b + 10*a^3*b^2 + 10*a^2*b^3 + 5*a*b^4 + 1*b^5
? Python 实现(完整版)
def generate_yanghui(n):
"""
生成杨辉三角的前 n+1 行(第0行到第n行)
:param n: 最大行号
:return: 列表,每个元素是一行(列表)
"""
triangle = []
for i in range(n + 1):
# 初始化一行,全部填充1,长度 i+1
row = [1] * (i + 1)
# 修改中间的元素(索引从1到i-1)
for j in range(1, i):
# 递推:上一行左边+上一行右边
row[j] = triangle[i - 1][j - 1] + triangle[i - 1][j]
triangle.append(row)
return triangle
def print_binomial_expansion(n):
"""
打印 (a+b)^n 的展开式
:param n: 指数
"""
# 获取第 n 行系数
row = generate_yanghui(n)[n]
terms = []
for k in range(n + 1):
coef = row[k]
term = ""
if coef != 1 or (n - k == 0 and k == 0):
term += str(coef)
if n - k > 0:
term += "a"
if n - k > 1:
term += "^" + str(n - k)
if k > 0:
term += "b"
if k > 1:
term += "^" + str(k)
terms.append(term)
print("(a+b)^{} = {}".format(n, " + ".join(terms)))
# 主程序
n = int(input("请输入行数: "))
tri = generate_yanghui(n)
print("杨辉三角:")
for i, row in enumerate(tri):
print("行{}: {}".format(i, row))
# 打印第5行系数
if n >= 5:
print("第5行系数:", tri[5])
# 打印 (a+b)^n 展开式
print_binomial_expansion(n)
运行示例(输入 5):
请输入行数: 5
杨辉三角:
行0: [1]
行1: [1, 1]
行2: [1, 2, 1]
行3: [1, 3, 3, 1]
行4: [1, 4, 6, 4, 1]
行5: [1, 5, 10, 10, 5, 1]
第5行系数: [1, 5, 10, 10, 5, 1]
(a+b)^5 = a^5 + 5a^4b + 10a^3b^2 + 10a^2b^3 + 5ab^4 + b^5
6. 杨辉三角与组合数的更多性质
6.1 每行之和等于 2ⁿ
因为 (1+1)ⁿ = 2ⁿ,展开后各项系数之和正好等于 2ⁿ。
例如第 5 行:1+5+10+10+5+1 = 32 = 2⁵。
6.2 斜线上的数字规律
- 第 1 条斜线(最左边)全为 1。
- 第 2 条斜线:1, 2, 3, 4, 5, … 表示自然数。
- 第 3 条斜线:1, 3, 6, 10, 15, … 是三角形数(可以组成等边三角形点的个数)。
- 第 4 条斜线:1, 4, 10, 20, … 是四面体数(三维的三角形)。
6.3 帕斯卡恒等式(递推基础)
组合数核心递推公式:
C(n, k) = C(n-1, k-1) + C(n-1, k)
这个公式就是杨辉三角中“上方两数之和”的数学表达。
7. 应用:用二项式定理简化复杂计算
7.1 估算 (1.01)^100
直接计算 1.01 的 100 次方很慢,但利用二项式定理展开:
(1+0.01)^100 = 1 + 100×0.01 + C(100,2)×0.01² + …
取前几项就能得到很好的近似值:约 2.7048(实际上 e ≈ 2.71828)。
编程中常用这种方法快速计算高次幂的近似值。
7.2 计算概率
抛 10 次硬币,恰好出现 6 次正面的概率是 C(10,6)/2¹⁰ = 210/1024 ≈ 0.205。
杨辉三角第 10 行第 6 个数就是 210,直接查表可得。
8. 练习题(附详细解答)
练习1:求 (x+2)^4 的展开式
思路:用二项式定理,系数是杨辉三角第 4 行:1, 4, 6, 4, 1。
注意每一项中 b=2,所以需要乘以 2 的相应次幂。
解答:
(x+2)⁴ =
C(4,0) x⁴·2⁰ + C(4,1) x³·2¹ + C(4,2) x²·2² + C(4,3) x¹·2³ + C(4,4) x⁰·2⁴
= 1·x⁴·1 + 4·x³·2 + 6·x²·4 + 4·x¹·8 + 1·1·16
= x⁴ + 8x³ + 24x² + 32x + 16
练习2:用递推方法(不使用阶乘)输出杨辉三角第 n 行的所有数
思路:可以像代码中那样生成整个三角形,但也可以只存一行递推。
下面给出 Python 中只计算第 n 行的递推方法(利用帕斯卡恒等式):
def get_row(n):
"""返回杨辉三角第 n 行(n从0开始)"""
row = [0] * (n + 1)
row[0] = 1
for i in range(1, n + 1):
# 从后向前更新,避免覆盖
for j in range(i, 0, -1):
row[j] = row[j] + row[j - 1]
return row
n = int(input("请输入行号: "))
print("第{}行:".format(n), get_row(n))
运行(输入 5)得到 [1, 5, 10, 10, 5, 1]。
9. 小结与相关指引
二项式定理和杨辉三角是“组合数学”的基石。通过编程,你可以:
- 快速生成任意行的系数
- 递推计算组合数而不必担心溢出
- 运用展开式解决概率、近似计算等实际问题
后续可以学习:
- 组合数的阶乘公式(及大数处理)
- 二项式系数的模运算(在竞赛中常用)
- 二项式定理的推广(如牛顿广义二项式定理)
- 杨辉三角与分形(如谢尔宾斯基三角形)的关系
掌握了这些,你在数学和编程竞赛中会发现自己多了一把“万能钥匙”。
例题精讲
已知杨辉三角中,第n行第k个数(从0开始计数)等于组合数C(n,k)。则(x+1)^6的展开式中,x^4的系数是多少?
二项式展开式中,项数等于指数n加1。
以下函数使用动态规划(杨辉三角递推)计算二项式系数C(n,k)。请补全递推部分。
int binomial(int n, int k) {
int C[n+1][n+1];
for (int i=0; i<=n; i++) {
C[i][0] = C[i][i] = 1;
for (int j=1; j<i; j++)
C[i][j] = ___;
}
return C[n][k];
}杨辉三角中,第5行(从第0行开始)的所有数字之和是多少?
以下代码用递归方式计算二项式系数C(n,k),基于杨辉三角递推。请补全base case。
int C(int n, int k) {
if (___ || ___) return 1;
return C(n-1, k-1) + C(n-1, k);
}