第 3 章:线性规划数学模型 —— 应用题列方程的艺术¶
场景: 第 1 章我们用奶茶店例子建立了直觉。现在让我们系统学习如何将任何实际问题转化为标准的线性规划模型。这个过程就像"应用题列方程"——理解题意 → 设未知数 → 列式子 → 验证。
3.1 数学模型的三要素¶
任何一个线性规划问题都由三个要素组成:
\(x \rightarrow z \rightarrow c\)
| 要素 | 回答的问题 | 数学表达 |
|---|---|---|
| 决策变量 | 我要决定什么? | \(x = (x_1, x_2, \dots, x_n)\) |
| 目标函数 | 我的优化目标是什么? | \(\max\) 或 \(\min \quad z = c^T x\) |
| 约束条件 | 我受到哪些限制? | \(Ax \le b, \ x \ge 0\) |
建模步骤口诀
- 问 :要什么?(最大化利润 or 最小化成本)
- 选 :选什么?(设决策变量)
- 算 :怎么算?(写目标函数)
- 限 :限制是什么?(列约束条件)
- 查 :检查是否线性
3.2 决策变量的选取¶
决策变量是模型的"未知数",选对了就成功了一半。
决策变量选择示例
问题 :某工厂生产 A、B 两种产品,每天各生产多少?
错误选择 :设"利润"为 \(x\) - 原因:利润是你想优化的结果,不是你直接能控制的决策
正确选择 :设 \(x_A\) = 每天生产 A 产品的数量,\(x_B\) = 每天生产 B 产品的数量 - 原因:这些是你可以直接控制的数量,利润由它们决定
决策变量选取原则¶
| 原则 | 说明 | 例子 |
|---|---|---|
| 直接可控 | 变量代表你直接能决定的量 | 产品数量、运输量 |
| 非负性 | 通常 \(x \ge 0\) | 产品不能生产负数 |
| 独立性 | 尽量让变量之间独立 | 避免冗余变量 |
3.3 目标函数的构建¶
目标函数是你想要优化的表达式。在商业问题中,通常是:
- 最大化 :利润、收益、市场份额
- 最小化 :成本、时间、距离、浪费
目标函数构建示例
问题 :某工厂生产两种产品,单位利润分别为 5 元和 3 元。
决策变量 :\(x_1\) = A 产品数量,\(x_2\) = B 产品数量
目标函数 : \(\max \quad z = 5x_1 + 3x_2\)
解读 :每多生产 1 单位 A 产品,总利润增加 5 元。
3.4 约束条件的构建¶
约束条件描述了你面临的资源限制和业务规则。
约束条件构建示例
问题 :继续上面的例子。生产需要:
- 原材料:每单位 A 需要 2 单位,每单位 B 需要 1 单位,总共不超过 10 单位
- 工时:每单位 A 需要 1 单位,每单位 B 需要 2 单位,总共不超过 8 单位
约束条件 : \(2x_1 + x_2 \le 10\) (原材料约束)
\(x_1 + 2x_2 \le 8\) (工时约束)
\(x_1 \ge 0, \ x_2 \ge 0\) (非负约束)
3.5 完整建模实例¶
实例 1:生产计划问题¶
完整建模
问题描述: 某家具厂生产桌子和椅子。每张桌子售价 45 元,利润 30 元;每把椅子售价 25 元,利润 10 元。
生产一张桌子需要 4 单位木材和 2 单位工时;生产一把椅子需要 1 单位木材和 1 单位工时。
每天可用的木材是 200 单位,工时是 80 单位。
市场分析表明每天椅子的需求量至少是桌子的 2 倍。
问:每天应生产多少桌子和椅子,使总利润最大?
建模步骤:
-
设变量 \(x_1\) = 每天生产的桌子数, \(x_2\) = 每天生产的椅子数
-
写目标函数 \(\max \quad z = 30x_1 + 10x_2\)
-
列约束 \(4x_1 + x_2 \le 200\) (木材约束)
\(2x_1 + x_2 \le 80\) (工时约束)
\(x_2 \ge 2x_1\) (需求比例约束)
\(x_1 \ge 0, \ x_2 \ge 0\) (非负约束)
- 标准化需求约束 (移项) \(4x_1 + x_2 \le 200\)
\(2x_1 + x_2 \le 80\)
\(-x_2 + 2x_1 \le 0\)
import numpy as np
A = np.array([
[4, 1], # 木材约束
[2, 1], # 工时约束
[2, -1] # 需求约束(x2 >= 2x1 → 2x1 - x2 <= 0)
])
b = np.array([200, 80, 0])
c = np.array([-30, -10]) # min 形式取负
print("约束矩阵 A:")
print(A)
print(f"\n资源上限 b: {b}")
print(f"目标函数系数 c (min 形式): {c}")
渲染效果:
3.6 线性规划建模常见陷阱¶
| 陷阱 | 错误描述 | 正确做法 |
|---|---|---|
| 忘记非负约束 | 变量可以为负(生产负数产品?) | 显式写出 \(x \ge 0\) |
| 约束方向写反 | \(\ge\) 写成 \(\le\) | 仔细检查资源是否够用 |
| 遗漏隐含约束 | 忘记需求上限等 | 回顾问题中的每个条件 |
| 目标函数系数错误 | 把成本当利润最大化 | 明确是 max 利润还是 min 成本 |
| 单位不一致 | 木材用"张"和"把"混用 | 统一转换为相同单位 |
3.7 模型验证与调试¶
建立模型后,需要验证:
验证清单
- 量纲检查 :检查每个约束左右两边的单位是否一致
- 边界检查 :让变量取极端值(如 \(x_1=0, x_2=0\)),看约束是否满足
- 经济性检查 :最优解是否与直觉相符?
- 可行性检查 :是否存在可行解?(至少 \(x_1=0, x_2=0\) 总是可行)
def validate_model(A, b, x):
"""验证解 x 是否满足所有约束"""
violations = []
for i, (row, limit) in enumerate(zip(A, b)):
lhs = np.dot(row, x)
if lhs > limit:
violations.append(f"约束 {i+1}: {lhs:.2f} > {limit}")
if violations:
print("❌ 约束违反:")
for v in violations:
print(f" {v}")
else:
print("✅ 所有约束满足")
print(f" 目标函数值: z = {np.dot(c, x):.2f}")
# 验证 x = (10, 40) 是否可行
x_test = np.array([10, 40])
print("验证 x = (10, 40):")
validate_model(A, b, x_test)
print("\n验证 x = (20, 40):")
validate_model(A, b, np.array([20, 40]))
渲染效果:
要点总结¶
- 线性规划模型 = 决策变量 + 目标函数 + 约束条件
- 决策变量要选直接可控的量
- 目标函数 max 或 min 取决于业务目标
- 约束必须覆盖所有限制,包括隐含约束
- 建模后要验证:量纲、边界、经济性、可行性
课后练习¶
- 建模练习 :为以下问题建立线性规划模型:
某投资者有 100 万元可用于投资。有三种项目: - 项目 A:年收益率 8%,风险系数 3 - 项目 B:年收益率 12%,风险系数 7 - 项目 C:年收益率 6%,风险系数 1
规则: - 总投资不超过 100 万 - 平均风险系数不超过 4 - 项目 A 至少投资 20 万
建立模型使年总收益最大。
-
建模练习 :某运输问题——从两个仓库向两个门店送货,运费和供应量如下,求最小运费。
-
思考题 :如果一个问题中的约束条件不是"不超过"而是"恰好等于",模型需要做什么修改?
下一章预告: 模型建好了,如何求解?第 4 章将介绍 图解法 ——用几何直观理解线性规划的最优解。这是最简单但也最直观的方法,特别适合两个变量的问题。