☰
Excel搞定带≥约束的线性规划:大M法与规划求解实战
2026/10/17 1:05:16 网站建设 项目流程

遇到带“≥”约束的线性规划问题,不少人的第一反应是装Python调库,其实Excel里就能搞定。大M法是单纯形法处理这类约束的标准扩展,而Excel里更省事的做法是直接用“规划求解”求解器自动计算。这篇文章我打算同时聊透两条路线:一是规划求解自动算,适合日常工作快速出结果;二是用Excel单元格公式手动搭一张大M单纯形表,适合搞懂原理、应付考试或者做模型校验。两条路线都会用同一个算例完整走一遍,文章最后再聊聊M值应该取多大、Solver引擎怎么选、手算表有哪些容易翻车的地方。

1. 为什么线性规划求解绕不开大M法:全是“≥”和“=”的锅

1.1 单纯形法有个先天要求:先要有初始基变量

单纯形法的标准形式要求所有约束都是等式,并且右边常数非负。对于“≤”类型的约束,直接引入松弛变量就能凑出一个单位矩阵,比如“x1 ≤ 4”写成“x1 + x3 = 4”,x3天然就是基变量,第一轮迭代的初始基就有了。

问题出在“≥”和“=”约束上。

“3x1 + 2x2 ≥ 18”改写成等式时,先要减去一个剩余变量,变成“3x1 + 2x2 - x5 = 18”。但这一减,x5前面的系数是“-1”,矩阵里没法直接挑出一组单位向量当初始基。没有初始基,单纯形表的第一行检验数就算不出来。

这时候就得请人工变量出场。人工变量的作用很直白:在等式约束里硬加一个单位向量,让这个约束“看起来”有了基变量。还是上面那条,写成“3x1 + 2x2 - x5 + x6 = 18”,x6就是人工变量。它本身没有实际业务含义,纯粹是借来凑初始基的“临时工”。

既然是临时工,就不能让它赖在最优解里。大M法的思路是给人工变量在目标函数里挂一个巨大的惩罚系数M。求最大值时人工变量系数是“-M”,求最小值时人工变量系数是“+M”。只要M足够大,最优解里人工变量就一定会被挤出基变量,变成0。如果最后最优解里人工变量还留在基里且取值大于0,说明原问题没有可行解。这个判据后面还会用到。

1.2 一个带“≥”约束的算例,后续全程用它演示

我选了一个教材里非常经典的例子,特点是同时包含“≤”和“≥”约束:

max z = 3x1 + 5x2 约束: x1 ≤ 4 2x2 ≤ 12 3x1 + 2x2 ≥ 18 x1, x2 ≥ 0

标准化过程如下:

  • 第一条约束加松弛变量x3:x1 + x3 = 4
  • 第二条约束加松弛变量x4:2x2 + x4 = 12
  • 第三条约束减剩余变量x5,再加人工变量x6:3x1 + 2x2 - x5 + x6 = 18

目标函数变成:

max z = 3x1 + 5x2 + 0x3 + 0x4 + 0x5 - M·x6

初始基变量就是x3、x4、x6。初始单纯形表如下:

基变量cBbx1x2x3x4x5x6θ
x3041010004
x4012020100—
x6-M183200-116
σ——3+3M5+2M00-M0—

检验数行σ的计算逻辑在后面手算表章节会详细讲。只看结果:σ1 = 3 + 3M,σ2 = 5 + 2M。因为M很大,3M明显大于2M,所以第一轮进基变量是x1而不是x2。很多初学者会纠结“3比5小,为什么不是x2先进基”,答案就是M的惩罚效应放大了x1的净收益。

这个例子的最终最优解是x1 = 4,x2 = 6,z = 42。整个求解过程需要四次转轴迭代,中间还会出现“人工变量已经出基但检验数仍为正”的情况,非常适合用来演示完整流程。

1.3 M到底取多大:“足够大”不是“越大越好”

M在理论上的要求是“比任何有限目标函数收益都大”,所以叫“足够大”。但在Excel里实际填数值时,很多人会顺手填10亿,结果表里的检验数动辄上亿,小数位的有效精度被挤占,明明还差0.5没到最优,看起来却像是0。

实践中的经验是:手算表里M取100或者1000就够了。上课考试时为了保证计算不崩,甚至可以取10000,但不要取1E9这种暴力值。如果问题规模较大或系数本身差异非常大,更稳妥的做法是改用两阶段法,完全绕开M的取值问题。两阶段法和“大M法”本质等价:第一阶段先让所有人工变量出基,第二阶段再在原问题上用单纯形法继续迭代。Excel规划求解内部做的其实就是这类处理,用户根本不需要自己设置M。

2. 全自动路线:Excel规划求解(Solver)的正确打开方式

2.1 从加载项到求解引擎:一次配置备查清单

规划求解在Excel里默认是不显示的,需要先手动加载。路径是这样:

  1. 点击“文件”→“选项”→“加载项”。
  2. 在底部“管理”下拉框里选择“Excel加载项”,点击“转到”。
  3. 在弹出的对话框中勾选“规划求解加载项”,点击确定。

操作完成后,“数据”选项卡最右侧会出现“规划求解”按钮。如果你用的是Mac版Excel,路径略有差异,通常是在“工具”→“加载项”里勾选,但功能完全一致。

有个容易踩的坑:公司电脑如果是精简安装的Office,加载项列表里可能找不到“规划求解加载项”。解决办法是重新运行Office安装程序,在“Office共享功能”下勾选“规划求解”。装了WPS的朋友要注意,WPS表格里面也有类似功能但菜单名称和位置不同,操作逻辑大体相似。

2.2 模型录入与三个关键选项

打开规划求解对话框后,把上面的算例录入进去。我习惯在建表时用单元格引用,而不是把数字直接填进对话框,这样后续改参数方便。

目标单元格填目标函数所在单元格,比如$B$1,选择“最大值”。可变单元格填决策变量区域,比如$B$2:$C$2。

约束的录入是重点。Solver支持“≤”“≥”“=”三种关系,直接在“添加约束”里写就行。“≥”约束在Solver里会自动处理,不需要像大M法那样手工引入剩余变量和人工变量。这是Solver和手算表最本质的区别:求解引擎内部已经把两阶段法或大M法封装好了。

录入完毕,点开“选项”,有三个地方需要注意:

  • 勾选“使非约束变量为非负数”。这一步等于自动添加“x1 ≥ 0,x2 ≥ 0”。漏勾的话可能算出负数解,在产量、人员、金额这类业务场景里纯属事故。
  • 求解方法务必选择“单纯线性规划”。Solver提供了三个引擎:LP单纯形(单纯线性规划)、GRG非线性、演化。线性规划问题必须用第一个。很多人从头到尾用默认的GRG非线性求解线性模型,轻则结果不准,重则提示“已达最大迭代次数”然后返回一个看似合理的错误解。
  • 迭代次数和精度一般保持默认即可。如果是几百个变量的中型题目,可以适当把最大求解时间调高到300秒。

2.3 求解结果与报告解读

点击“求解”,Solver会弹出“已找到一解”的提示。选择“保留规划求解的解”,Excel会把决策变量和目标函数单元格直接更新为结果。用上面的算例,你会得到x1 = 4、x2 = 6、z = 42,和手算大M法的结果完全一致。

对话框右侧还有一个“报告”区域,可以生成三种报告:

  • 运算结果报告:列出目标单元格、可变单元格、约束的最终值和状态。
  • 敏感性报告:给出目标函数和约束右端值的允许变化范围,做“如果……会怎样”的分析时很有用。
  • 极限值报告:显示每个决策变量在当前解下的上下限。

实际工作中我大多只需要运算结果报告,敏感性报告在做产能规划类问题时才会用到。报告是单独生成一张新工作表的,直接用就行,不需要额外处理。

3. 手算路线:用Excel公式自己搭一张大M单纯形表

3.1 表头布局与检验数公式

想搞懂大M法内部逻辑,最好的方式是自己搭一张单纯形表,用Excel公式辅助计算,迭代过程手动操作。这种做法的好处是每一步都看得见,考完试、讲给同事听也都用得上。

工作表布局建议这样安排:

  • A列:基变量名
  • B列:基变量对应的cB值
  • C列:右端项b
  • D列到I列:x1、x2、x3、x4、x5、x6六列的系数
  • J列:θ比值

举个例子,假设初始表中第2行是x3,第3行是x4,第4行是x6,那么第5行专门放检验数σ。

检验数公式是关键。σ_j的计算逻辑是:目标函数里该变量的系数,减去“当前基变量cB与系数列对应乘积的合计”。在Excel里写出来就是:

=D$7 - SUMPRODUCT($B$2:$B$4, D2:D4)

这里D$7存放的是目标函数中x1的原始系数3,$B$2:$B$4是当前基变量x3、x4、x6的cB值(0、0、-M),D2:D4是x1这一列在三个约束行里的系数(1、0、3)。SUMPRODUCT求出的就是cB乘以a_j的和。这个公式向右拖动就能算出所有检验数,相当顺手。

θ比值列也要用公式算,但要带判断条件:

=IF(D2>0, C2/D2, "")

这个公式的意思是:只有进基变量所在列的系数为正时,才算b除以系数的比值;系数为负或零时留空,不参与最小比值筛选。很多人手算时会把所有行都除一遍,结果选错出基变量,白白多迭代两轮。

3.2 转轴操作的Excel手法:每轮都做“复制→粘贴值”

每次迭代的核心动作包括:找出最大的正检验数确定进基变量,从θ列中选最小正值确定出基变量,然后做行变换。

行变换的规则是:主元行除以主元系数得到新主元行;其他行减去“该行主元列系数乘以新主元行”。在Excel里手算时,最容易出错的环节是公式引用错位。我的习惯是新建一块区域,用公式引用当前表做变换,算完后立刻“复制”→“选择性粘贴数值”覆盖回原表区域,把公式彻底打成纯数字,避免后续操作产生循环引用。

举个例子,初始表第一轮迭代:最大检验数是x1列的“3+3M”,所以x1进基。θ列中x3行是4/1=4,x6行是18/3=6,x4行系数为0不参与,最小值是4,所以x3出基。主元位置就在x1列与x3行的交叉点,主元系数是1。

新表的x3行变成原x3行除以1,还是原样。x4行不受影响,因为x4行x1系数是0。x6行要把x1系数消成0,所以执行“原x6行减去3倍的新x3行”。这些数字看起来简单,实际在Excel里操作时,我强烈建议每轮做完都在旁边留一块“验算区”,把基变量取值代回原三条约束,确认等号成立再继续下一轮。

3.3 从这个例子看完整四轮迭代:最优解不会自己跳出来

这个算例完整跑完需要四次转轴。我把每一轮的关键变化整理成一张表,方便你对着自己的表核对:

轮次进基变量出基变量迭代后的基变量取值当前z值
第1轮x1x3x1=4,x4=12,x6=612 - 6M
第2轮x2x6x1=4,x2=3,x4=627
第3轮x3x4x1=2,x2=6,x3=236
第4轮x5x3x1=4,x2=6,x5=642

第2轮的时候人工变量x6刚好出基,很多初学者会误以为“人工变量走了就算完了”。但其实第3轮迭代结束后,检验数里仍然存在正的σ5,最优解尚未到达,需要继续迭代。这个细节很值得注意:单纯形法迭代到什么程度能停,唯一依据是检验数是否全部满足最优性条件,而不是“看起来差不多”。

第4轮迭代结束后,所有非基变量检验数都小于等于0,此时才可以停手。最终解x1=4、x2=6、z=42,代回原约束验证:

  • x1 = 4,满足“x1 ≤ 4”,取等号;
  • 2x2 = 12,满足“2x2 ≤ 12”,取等号;
  • 3×4 + 2×6 = 24 ≥ 18,满足“≥约束”且未被逼到边界。

这个解的含义是:资源限制同时卡在第一和第二条约束上,第三条约束还有6个单位富余。

3.4 手算表易错点与自我检查清单

手算大M法翻车概率最高的几个位置,我逐个说清楚。

第一,检验数必须使用当前基变量的cB。迭代几轮后基变量早就变了,如果还抱着初始的cB做SUMPRODUCT,算出来的全错。我见过很多人在第三轮开始检验数越算越离谱,原因基本都是这个。

第二,比值检验必须忽略非正分母。系数为负说明该行方向与进基变量变化方向相反,不能参与比值筛选;系数为0说明进基变量与该行无关,也不参与。

第三,每轮迭代后基变量列的取值必须非负。如果某一行右端项b变成负数,说明换基换错了或者主元选错了,立刻回退重算。

第四,最优解出来后一定代入原约束验证。z值再漂亮,约束不满足也是白搭。这个检查习惯能拦住九成的手误。

4. 用VBA把表算成自动化:迭代逻辑与实现边界

4.1 单纯形法主循环的骨架

如果你经常处理同一类线性规划模型,手算表每轮复制粘贴数值也会烦。这时候可以考虑写一个简单的VBA宏,把换基迭代的逻辑交给代码。

单纯形法的主循环骨架并不复杂,核心逻辑大概是这样的:

  • 找出所有检验数中最大的正值,所在列就是进基变量列。
  • 如果最大检验数小于等于0,循环结束。
  • 在进基变量列中,对所有大于0的系数行计算θ比值,取最小的行作为出基变量行。
  • 如果进基变量列所有系数都小于等于0,说明目标函数无界,直接终止。
  • 执行行变换:主元行除以主元系数,其他行减去“该行主元系数乘以新主元行”。
  • 更新基变量和cB,回到第一步。

写成VBA的示意片段是这样的:

' 找到最大正检验数对应的列,nVars为变量个数 Dim pivotCol As Long, j As Long Dim maxSigma As Double pivotCol = 0 maxSigma = 0.0000000001 ' 加一个极小容差,避免浮点误差误判 For j = 1 To nVars If rngSigma(j) > maxSigma Then maxSigma = rngSigma(j) pivotCol = j End If Next j If pivotCol = 0 Then MsgBox "已找到最优解" Exit Sub End If

这段代码我特意在判断条件里加了一个0.0000000001的容差。原因是Excel浮点数在多次除法后会留下极小残余,比如0.00000000000001这种接近零的数,按严格大于0判断会被当成正检验数,白白多迭代一轮。这个细节手算表里遇不到,写自动化时一定要处理。

4.2 与其自己造轮子,不如用SolverSolve一行调用

完整写一遍单纯形法VBA,少说也要两三百行,还要处理退化、循环、无界、无可行解这些边界情况。对于多数实际业务,我的建议是:学习进度条走到“能写主循环骨架”就足够了,真正要批量求解时直接调用Excel自带的规划求解引擎。

Solver本身暴露了VBA接口。前提是在VBA编辑器里打开“工具”→“引用”,勾选“Solver”。之后就能直接写代码:

Sub RunSolver() SolverReset SolverOK SetCell:="$B$1", MaxMinVal:=1, ByChange:="$B$2:$C$2" SolverAdd CellRef:="$A$5:$A$7", Relation:=1, FormulaText:="$C$5:$C$7" SolverAdd CellRef:="$B$2:$C$2", Relation:=3, FormulaText:="0" SolverOK SetCell:="$B$1", MaxMinVal:=1, ByChange:="$B$2:$C$2", Engine:=1 SolverSolve UserFinish:=True End Sub

简单解释几个参数:MaxMinVal为1表示求最大值,2表示求最小值;Relation为1表示“≤”,2表示“≥”,3表示“等于”;Engine为1时对应“单纯线性规划”引擎。最后一行UserFinish:=True的意思是让Solver算完不弹“是否保留结果”的对话框,直接把结果写到工作表中,适合脚本无人值守跑数。

4.3 自动化版本的坑不比手算少

写自动化之前要清醒一点:如果模型本身没有可行解,或者目标函数无界,任何纯手工实现的单纯形法VBA都会出问题。Solver在碰到这两种情况时会有明确提示,这是自研代码很难做得完善的领域。

再就是M值的敏感度问题。虽然Solver内部用的是两阶段法不需要用户设置M,但如果你是在自己的VBA纯手写大M法,M取了不合适的值,结果该解的没解出来,该停止的没停止。所以自动化路线我只推荐用官方Solver接口,不建议在公司环境里跑自己写的单纯形法全流程,除非你只是想拿它当学习验证工具。

5. 两条路线怎么选:对比、取舍与翻车案例复盘

5.1 选型对照:手算表与规划求解的真实差异

很多读者会纠结一个问题:既然Solver一键就能搞定,为什么还要学手算大M法?这个问题的答案可以从几个维度看:

对比维度手算单纯形表规划求解Solver
上手速度需要先理解检验数、人工变量会填表就能用,十分钟学会
求解透明程度每一步迭代都可见,适合教学和验证黑盒,只给最终解
适用规模手工最多跑几十个变量,再多算不动几百上千个变量也没问题
学习价值极高,能真正理解单纯形法原理几乎为零
对M值的敏感度需要手动设置,存在精度风险内部自动处理,无需关心
自动化批量处理非常困难可配合VBA批量调用

真实场景里,我的建议很简单:学习阶段先手算,遇到模型先用Solver拿结果,需要向别人解释“为什么是这个最优解”时再用手算表辅助验证。如果业务模型每星期都要跑一次,直接写个SolverSolve的宏一键出数。

5.2 几个我踩过的具体翻车案例

下面这些坑都是我自己实际操作中遇到过的,逐一列出来算作前车之鉴。

第一个坑是忘记勾选“使非约束变量为非负数”。有一次用Solver跑一个生产排程模型,出来的结果里x1竟然是个负值,产量为负数在业务上完全说不通。后来检查才发现是选项没勾。从那次以后,我每次打开规划求解对话框的第一件事就是检查这个复选框。

第二个坑是用错了求解引擎。早期我对Solver不熟,拿到线性问题就用默认的GRG非线性引擎去求解。结果要么迭代半天不收敛,要么收敛到一个明显不合理的局部解。换成“单纯线性规划”引擎之后,速度和精度都立刻正常。记住:线性问题用线性引擎,非线性问题才考虑GRG。

第三个坑是手算大M法时M值设得太大。我在一个比较简单的问题里把M设成了1E9,结果检验数全是几亿的数量级,真正的最优性判断反而被淹没在浮点误差里。后来统一改用M=1000,配合两阶段法思路互相印证,问题再没出现过。

第四个坑是转轴操作时复制粘贴引用错位。手算表迭代到第三轮,有时候我会图省事直接拖动公式,结果某一行引用了已经过时的基变量cB区域,检验数全部乱掉。应对的办法是:每轮迭代完成后,先把整块表做一次“选择性粘贴数值”,把公式固化,再做下一轮的行变换。这个小习惯能省掉大量排错时间。

第五个坑是最优性判断符号搞反。求最大值时,最优条件是所有非基变量检验数都小于等于0;求最小值时则相反,所有检验数都大于等于0。很多人解min问题时还在按“大于0进基”的逻辑走,结果迭代到目标值开始不降反升才意识到方向错了。我个人的习惯是:遇到min问题,先心算转成max问题再进单纯形表,宁可多写一步也不拿符号做赌注。

5.3 我的实际工作流程

经过多次调整,我自己在混用两条路线时形成了这样一个固定流程:先打开Solver快速求解并生成运算结果报告,拿到基础答案后,把手算表作为独立验算通道跑一遍关键模型。如果两者结果一致,基本可以放心交付;如果出现偏差,再往前检查约束录入和M值设置,往往能发现模型定义层面的问题。

这个流程的优点是把Solver的“快”和手算表的“看得见”结合起来。平时给同事讲方案时,我不会只丢一个“Solver算出来是42”的结论,而是连转轴过程都说清楚。对方看到x1、x2一步步从初始表变到最优解,信服程度完全不同。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询