优化模型
主讲人:复旦大学数学科学学院 曹沅
引言:数学规划的基本框架
一个数学规划(优化模型)问题一般由三部分组成:
- 决策变量(decision variables):需要求解的未知量,记为 ;
- 目标函数(objective function):衡量方案优劣的函数 ,问题是求它的最大值或最小值;
- 约束条件(constraints):决策变量必须满足的等式或不等式关系。
满足全部约束条件的 称为可行解,全体可行解构成可行域,使目标函数取到最优值的可行解称为最优解,对应的目标函数值称为最优值。
按目标函数、约束条件的性质,可以对数学规划分类:
| 分类依据 | 类型 |
|---|---|
| 目标/约束是否线性 | 线性规划(LP) / 非线性规划(NLP) |
| 决策变量是否要求整数 | 整数规划(IP,含 0-1 规划) / 连续规划 |
| 目标函数是否二次、约束是否线性 | 二次规划(QP) |
| 是否混有连续变量与整数变量 | 混合整数规划(MIP) |
线性规划(Linear Programming, LP)
标准形式
任何线性规划都可以通过下述等价变换化为标准形(目标求最小、约束为等式、变量非负):
- ;
- 不等式 可引入松弛变量 化为 ;
可引入剩余变量 化为 ; - 自由变量 (无符号限制)可写成两个非负变量之差 。
这一步是后续单纯形法能够统一处理各种线性规划的基础。
例 营养问题
一个养鸡场用 种饲料配制一批配合饲料。
要求这批配合饲料中必须含有 种不同的营养成分,且要求 营养成分的含量不低于 ;
已知每单位(克或千克)的 饲料中含有 营养成分 ,每单位 饲料的价格为 。在保证营养的前提下,问采用怎样的配方能使这批配合饲料的费用最小?
设 为 饲料的用量,由已知条件可得下表(行是 种营养成分及其下限,列是 种饲料):
则 就是这批配合饲料中 营养成分的总含量,按题意
这批配合饲料的总费用是 ,于是问题归结为
向量、矩阵写法:
其中
——决策变量, ——目标函数,不等式(或等式)——约束条件;若目标函数、约束条件关于决策变量都是线性的,就称(1.1)是线性规划问题(Linear Programming, LP)。
单纯形法的基本思想
- 可行域 是凸多面体,若最优值有限,则一定可以在某个顶点(基本可行解)处取到。
- 单纯形法的思路是:从一个顶点出发,沿着使目标函数下降(或上升)的棱不断转移到相邻顶点,直到找不到能继续改进的方向为止,此时即为最优顶点。
- 每一步"转移顶点"对应一次换基(选择换入变量与换出变量),当问题存在退化基本可行解时,简单的换基规则可能出现基反复循环、算法不终止的情况;理论上可以证明,采用 Bland 规则(在换入/换出变量有多个候选时,恒选下标最小者)的单纯形法不会出现死循环,从而保证算法有限步终止。
- 在 Matlab 的优化工具箱中,
linprog函数封装了求解线性规划的数值方法(内点法或单纯形法),可以直接调用,不必手工迭代。
linprog 函数的调用格式是:
1 | [x, fval] = linprog(f, A, b, Aeq, beq, lb, ub) |
其中 f 是目标函数系数向量(默认求 ),A,b 对应不等式约束 ,Aeq,beq 对应等式约束,lb,ub 是变量的上下界;若无某类约束,用 [] 占位。
实例
改造成矩阵向量形式:
Matlab 代码:
1 | clear |
注:原稿代码中出现的
load hald;是 Matlab 自带统计工具箱示例数据集(Hald 水泥数据),与本题无关,属于误写,已在上面的代码中删去。
计算结果:
1 | Optimization terminated. |
所以最优解是 ;最优值是 。
手工验证(图解法/顶点枚举): 由于只有两个变量,可行域是一个凸多边形,最优解必在顶点处取得,逐一列出顶点并代入目标函数:
| 顶点来源 | 顶点坐标 | |
|---|---|---|
| ,(第一条件起作用,因为它比 更紧) | ||
| ,取三条约束中最紧的 | ||
| 第一、二条约束交点: |
解交点方程:由 乘 、 乘 相减,得 ,代回得 。四个顶点中 的最小值在 处取得,与 linprog 结果一致,从而验证了解的正确性。
另一种调用方式(显式列出各类约束):
1 | clear |
整数规划(Integer Programming, IP)
相关竞赛题: 2003年 CUMCM B题(露天矿生产的车辆安排),2005年 CUMCM B题(DVD在线租赁问题)。
有些实际问题中决策变量部分或全部只能取整数,如人数、项目数、工厂数等,这类问题称为整数规划(IP)。更加特别地,若决策变量只能取 0 或 1,则称为0-1规划(Binary Integer Programming, BIP)。整数规划的求解本质上比线性规划困难得多(一般是 NP-难问题),常见方法有分支定界法、割平面法、动态规划、以及针对特殊结构(如指派问题)的专门算法。
例 0-1背包问题
设一个背包的容量为 ,要从 件物品中选择若干件装入背包,设 物品的体积为 ,价值为 ,问应该将哪些物品装入背包可使总价值最大?
记决策变量
则总价值(目标函数)为:,
总体积(约束条件)为:,
所以0-1背包问题就是:
这是最简单的0-1规划问题,是很多整数规划、0-1规划的基础。它可以用回溯法、分支定界法、动态规划等方法精确求解,也可以用贪心算法(按 单位价值排序装填)求近似解。经典的动态规划递推为:设 为只考虑前 件物品、容量为 时能得到的最大价值,则
Matlab 中有一个函数 bintprog 可以求解0-1规划问题(Binary Integer Programming),调用格式是:
1 | [x, fval] = bintprog(f, A, b, Aeq, beq) |
说明:
bintprog是较早版本 Matlab 优化工具箱中的函数,在较新版本中已被移除,官方推荐改用能处理混合整数线性规划的intlinprog(调用格式[x,fval] = intlinprog(f,intcon,A,b,Aeq,beq,lb,ub),其中intcon是取整数(0-1 变量取lb=0,ub=1且整数)的变量下标)。下文仍按原讲义使用bintprog演示建模思路,读者在新版 Matlab 中可等价替换为intlinprog。
实例
设 ,,。
问题(转化为求 ):
1 | clear |
所以最优解是:,此时总体积 (恰好装满),原问题(求 )的最优值是 。
实例
1 | clear |
所以最优解为 ,最优值为 。校验:;;;,全部约束满足。
例 分配问题(Assignment Problem / 指派问题)
给 个人分配 项工作,每人一项工作;已知 人完成 工作需时间(或费用),问怎样分配使得完成全部工作的总时间(或费用)最少?
建模: 设决策变量是
则花费总时间(目标函数):。
对 人来说,只分配给一项工作(约束条件):
对 工作来说,只分配给一个人(约束条件):
所以分配问题就是0-1规划:
匈牙利算法要点(专用于分配问题,比通用整数规划算法高效得多,多项式时间 ):
- 对费用矩阵 ,每行减去该行最小元素,再每列减去该列最小元素,得到含 元素的矩阵;
- 用最少数目的横线、竖线覆盖矩阵中全部 元素;若覆盖直线数等于 ,则可以从 元素中选出一组「独立 0 元素」(每行每列恰有一个),对应的指派即为最优解;
- 若覆盖直线数小于 ,则在未覆盖元素中找最小值 ,未被覆盖的行都减去 ,被覆盖的列都加上 ,回到第 2 步。
由于分配问题结构特殊,可行域是双随机矩阵(每行每列和为 1 的 0-1 矩阵)的顶点集合,恰好是置换矩阵,这保证了匈牙利算法给出的解一定是整数解,无需分支定界。
实例
最简单的分配问题,2个人分配2项工作,工作需时(小时)矩阵为
答案显然:第一个人做第一项工作,第二个人做第二项工作,共需要时间 4 小时;否则(交叉分配)共需要 6 小时。
对 的式 (2.1) 做改造:将二维足标改为一维足标,,则约束
所以问题可写成:
1 | clear |
即 ,第一人做第一项工作,第二人做第二项工作,总时间 小时,与直觉一致。
另一种解法: 部分求解器(如早期 bintprog)只接受不等式约束,可以把一个等式拆成两个反向不等式,例如:
对全部 4 个等式约束都作这样的拆分,问题等价地变成只含不等式约束的0-1规划:
1 | clear |
两种建模方式给出完全相同的结果,说明「等式拆两个不等式」的等价变换是正确的。
思考题 的分配问题,工作需时(小时)矩阵分别为
请仿照实例,将二维下标改写为一维、列出等式(或不等式)约束,并用 bintprog(或 intlinprog)求解。
例 装载问题
某运输公司有 辆不同的卡车, 车的最大载重量为 ,现有 种货物可供装载,设 货物每件重量为 , 车装载 货物每件收费为 ,问怎样的装载方案使公司的收入最多?
建模: 记 表示 车装载 货物的件数(非负整数),
则总收费(目标函数):。
车装载的限制(约束条件):
所以得到整数规划问题:
显然,装载问题是0-1背包问题的推广:只要取 (只有一辆车),且每种货物都只有一件(此时 只能取 ),就退化为0-1背包问题。
分支定界法的基本思想
整数规划一般通过分支定界法求解,核心是「放松—分支—定界—剪枝」:
- 放松(Relaxation):先去掉整数约束,解相应的线性规划(LP 松弛问题),得到下界(对 问题);
- 分支(Branch):若 LP 最优解中某个应取整数的变量 取到非整数值 ,则以 和 为附加约束,把问题分成两支子问题;
- 定界(Bound):每解出一个整数可行解,就用其目标值更新上界(对 问题,当前已知最优整数解的目标值);
- 剪枝(Prune):若某支子问题的 LP 松弛最优值已经不小于当前上界,则该支不可能产生更优的整数解,无需继续分支,直接剪掉。
反复分支、定界、剪枝,直到所有分支都被剪掉或求出整数解为止,此时当前最优的整数解即为全局最优解。
实例
相应的 LP 松弛问题(去掉整数限制):
用 linprog() 解此 LP 问题,得
非整数,对它分支:将 LP 分成 LP11:LP + "";LP12:LP + "" 两部分,并以 作为全局下界。
解 LP11:;
解 LP12:;
两支的最优解都还含有非整数分量(),继续分支:
将 LP11 按 分成 LP211:LP11 + "";LP212:LP11 + "";
将 LP12 按 分成 LP213:LP12 + "";LP214:LP12 + ""。
解 LP211:;
解 LP212:;
解 LP213:;
解 LP214:。
与 都是整数解,是原 IP 问题的可行解,取其中较小者置上界 。因为 、,LP211、LP212 已不可能产生比 更优的整数解,剪枝;又 ,该整数解也不是最优的。于是得到 IP 问题的最优解
分支定界流程图:
(标 者为最终最优整数解)
例 选址问题
某地有 座煤矿, 矿每年生产 吨煤,原有火力发电厂一个,每年需用煤 吨,每年运行的固定费用(包括折旧费,不包括煤的运费)为 元。现要规划新建一个发电厂, 座煤矿每年开采的原煤全部供给这两个发电厂,现有 个备选厂址,若在 备选厂址建发电厂,每年运行的固定费用为 ,每吨原煤从 矿运到 备选厂址的运费为 ,每吨原煤从 矿运到原有厂的运费为 。问:新厂厂址应选在何处, 座煤矿开采的原煤应如何分配给两个发电厂,才能使每年的总费用(电厂运行的固定费用及原煤运费之和)最小?
建模: 座煤矿每年的总产量是 ,原有厂每年用煤 ,故新建厂每年可用煤
令决策变量:
记原有厂为 厂,被选中建新厂的备选厂址为 厂,即最终 、其余 。
设决策变量 为每年从 矿运到 厂的原煤数量 ,则每年总费用(目标函数)为
约束条件:
- 对 煤矿来说,每年生产的 吨煤全部运往原有厂与新建厂:
- 座煤矿运到原有厂的总煤量恰为原有厂的年用煤量:
- 若 备选厂址被选中(),则 座煤矿运到该厂的总煤量应恰为新厂年用煤量 ;若未被选中(),则运量应为 。这两种情形可统一写成:
- 个备选厂址中只能选一个建厂:
- 运量非负、选址变量为 0-1:
归纳后得到下面的规划问题:
注: 由最优解得出某个 ,该下标 就是要选中的备选厂址,即在 备选厂址建新厂;解出的 、 就是各煤矿分别运到原有电厂和新建电厂的煤量。
约束 3 中的 是决策变量 (0-1 变量)与常数 的乘积,仍是关于 的线性表达式,所以整个模型仍是(混合)线性约束;又因为 取实数、 取 0-1 整数,两类变量并存,所以(2.3)是混合整数规划问题(Mixed Integer Programming, MIP)。
例 旅行售货员问题(Travelling Salesman Problem, TSP)
在城市 的一位旅行售货员计划去城市 推销商品,最后回到 ,设 为从 到 的距离(,,)。问:应该怎样规划路线,使得对每个城市恰好访问一次,且总距离最短?
注1: 若将距离换成旅行时间或费用,一般不再对称,即 ,模型仍然适用(此时为「非对称 TSP」)。
注2: 若原路倒走算两条不同路线,由乘法原理,全部可能路线数为 (固定起点 ,其余 个城市全排列)。
建模: 设决策变量
则总距离(目标函数):。
显然应有 (不能原地停留),实现上常取 (充分大的常数,即所谓「大 M 法」)作为惩罚,使得优化过程自动避开 ,同时保持系数矩阵 是满秩、无特殊结构的方阵,便于统一编程;更严谨的做法是直接令自变量的上界 ub(ii下标)=0,从变量层面禁止自环。
对任一城市 ,在最优巡回路线中恰有一次为某段行程的起点、恰有一次为终点,即
但仅有以上两组约束还不够——它们只保证每个顶点的入度、出度都是 1,满足这两组约束的解可能是若干个互不相交的小回路(子回路)拼在一起,而不是经过全部 个城市的一条大回路。因此还需要**消除子回路(subtour elimination)**的约束。
消除子回路方法一(割集不等式): 要求任意把 座城市分成两个非空组后,两组之间一定有路线相连(否则就说明存在一个不含全部城市的孤立子回路)。设 是 的任一非空真子集,,则
的非空真子集共有
个,但由对称性( 与 产生的是同一族约束中互补的两条),实际独立约束数约为 量级,仍随 指数增长。
所以旅行售货员问题的完整模型为:
消除子回路方法二(MTZ 型/势函数不等式): 记城市集合 ,。对 的任意非空真子集 (),要求 内部使用的边数不超过 (否则 内部就形成了闭合回路):
直观地说,就是在 个城市中任意取出 到 个城市组成的子集,其内部不允许出现回路——这与方法一的割集不等式是等价的消子回路手段,实践中两者约束数目都随 指数增长,因此大规模 TSP 通常采用割平面法:先只加入部分约束求解,检测到子回路后再补充相应的不等式,逐步收紧。
TSP 算例
最简单的情形:,4个城市顺时针排成矩形,相互距离符合勾股数 :
其中 (惩罚自环)。不计方向,一共有 条本质不同的巡回路线(把每条路线和它的倒走算作同一条);若区分方向则有 条。两个显然的最优解互为倒走: 与 。
完整 Matlab 代码:
1 | %% TSP 问题(n = 4) |
手工验证: 对 只有 条本质不同回路,逐一计算总距离:
- :
- :
- :
最短路线为 ,对应 (即 ,其余 ),与直觉判断一致,且求得的最优值恰好是矩形周长 ,验证了模型与约束的正确性。
非线性规划(Nonlinear Programming, NLP)
一般形式与最优性条件
非线性规划的一般形式为
其中目标函数 或约束函数 中至少有一个是非线性的。与线性规划不同,非线性规划的最优解一般不在可行域的顶点取得,可能出现在可行域内部或边界的任意位置,且可能存在局部最优而非全局最优。
无约束情形():若 可微,极小点 处必有一阶必要条件 ;若 二阶可微,进一步要求 Hesse 矩阵 半正定(二阶必要条件)。据此可用梯度下降法、牛顿法等迭代求解。
约束情形: 引入 Lagrange 函数
若 是问题的(局部)最优解,且约束满足一定正则性条件,则存在乘子 ,使得 KKT 条件成立:
KKT 条件是非线性规划中最重要的最优性条件,是线性规划中「检验数判别最优」以及无约束优化中「梯度为零」的自然推广;当问题是凸规划( 凸、 仿射)时,KKT 条件不仅必要而且充分。
二次规划(Quadratic Programming, QP)
二次规划问题是最简单的一类非线性规划问题:目标函数是二次函数,约束条件是线性的等式或不等式。一般形式是:
其中 是对称矩阵,当 半正定时(3.0)是凸二次规划,此时局部最优解就是全局最优解,KKT 条件是最优的充要条件。
二次规划有许多应用,如时间调度、工作计划、设施分配等;某些复杂的非线性规划问题还可以通过逐次二次逼近转化为一系列二次规划问题(SQP 方法)来求解。而最著名的应用当属投资组合选择的 Markowitz 模型,该模型于 1952 年由 Harry Markowitz 提出,他也因此于 1990 年获诺贝尔经济学奖。
投资组合问题。 假设有 种金融项目(证券、基金)可供投资,设 是投资在 金融项目上的收益率(随机变量), 是收益率向量;设 是投资在 金融项目上的资金占总投资的比例(权重),于是
是投资组合的权重向量。因此
是投资组合的收益率,也是一个随机变量。记 为 金融项目收益率的数学期望(预期收益率),则由期望线性性,投资组合收益率的期望是
记 为 与 的协方差 ,协方差矩阵 。
Markowitz 用随机变量 (投资组合收益率)的方差来度量投资风险,即
由此得到三种常见的 Markowitz 模型:
模型1(限定风险、最大化收益): 投资组合收益率的期望最大,同时控制风险不超过给定水平 :
模型2(限定收益、最小化风险,与模型1对偶): 要求投资组合收益率的期望不低于给定水平 ,在此前提下使风险(方差)最小:
这是一个标准的凸二次规划(目标是凸二次型 ,约束线性),可以直接套用(3.0)的形式:取 (因为 quadprog 目标是 ,要使其等于 须令 ),。
模型3(加权平均模型,也称均值-方差效用模型): 用一个权衡系数 把模型1和模型2的两个目标函数加权平均,转成单一目标:
越大表示投资者越厌恶风险(更看重方差项), 越小表示越看重收益;令 在 内取遍所有值,对应的最优解 描出的 曲线就是著名的有效前沿(efficient frontier)。
Matlab 中求解二次规划的函数是:
1 | [x, f_opt] = quadprog(H, f, A, b, Aeq, beq, lb, ub, x0) |
算例(模型2): 设有 种资产,预期收益率 ,协方差矩阵
要求组合期望收益不低于 ,求方差最小的投资组合。代入模型2:
对应 quadprog 的参数:,;不等式 取 ,(因为 quadprog 只接受 形式,需要把 两边同乘 );,;。
1 | Sigma = [0.04 0.006 0.01; 0.006 0.09 0.02; 0.01 0.02 0.16]; |
用数值方法(等价于上述二次规划)实际求解,得到最优权重与最小方差:
验证:期望收益 ,恰好压在约束边界 上(因为高收益资产 3 的方差与协方差都较大,为了控制总风险,最优组合只把刚好达到目标收益所需的最少比例分配给它),说明收益约束是**起作用(active)**的,这与二次规划在凸问题下最优解落在约束边界的直觉一致。
小结
- 线性规划:目标、约束都线性,最优解在可行域顶点取得,用单纯形法(结合 Bland 规则保证不死循环)或内点法求解,Matlab 用
linprog。 - 整数规划:在线性规划基础上加上变量取整数(或 0-1)的要求,一般用分支定界法求解(对指派问题可用更高效的匈牙利算法),Matlab 早期用
bintprog,现推荐intlinprog。 - 非线性规划:目标或约束含非线性项,最优性条件由 KKT 条件刻画;其中二次规划(目标二次、约束线性)是最重要的特例,典型应用是 Markowitz 投资组合模型,Matlab 用
quadprog。
三类模型由简单到复杂层层递进,建模的核心步骤始终一致:明确决策变量 → 写出目标函数 → 列出约束条件 → 选择合适的求解算法/工具。
完整讲义
- Title: 优化模型
- Author: 椿咲璃音
- Created at : 2026-08-10 20:00:00
- Updated at : 2026-09-24 12:44:04
- Link: https://jackerytu.github.io/2026/08/10/优化模型/
- License: This work is licensed under CC BY-NC-SA 4.0.