0-1 规划不只是数模竞赛中的常见题型,也具备重要的现实意义。html
双十一促销中网购平台要求二选一,就是互斥的决策问题,能够用 0-1规划建模。python
小白学习 0-1 规划,首先要学会识别 0-1规划,学习将问题转化为数学模型。算法
『Python小白的数学建模课 @ Youcans』带你从数模小白成为国赛达人。编程
0-1 整数规划是一类特殊的整数规划,变量的取值只能是 0 或 1。app
0-1 变量能够描述开关、取舍、有无等逻辑关系、顺序关系,能够处理背包问题、指派问题、选址问题 、计划安排、线路设计 、人员安排等各类决策规划问题。进而,任何整数均可以用二进制表达,整数变量就能够表示为多个 0-1 变量的组合,所以任何整数规划均可以转化为 0-1 规划问题来处理。0-1 规划问题与运筹学中的不少经典问题也都有紧密联系。框架
在数学建模学习中,0-1 规划主要用于求解互斥的决策问题、互斥的约束条件问题、固定费用问题和分派问题。0-1 规划是数模竞赛的常见题型,国赛 B题常常有 0-1规划问题或能够转化为 0-1 规划问题。函数
0-1 规划的算法都比较复杂,大规模问题通常没有精确解法。本文仍然使用 PuLP 工具包求解 0-1 规划问题,该工具包的使用比较简单。建议本文读者重点关注 0-1 规划问题的分类及建模方法,把握哪些问题是 0-1 规划问题,是哪一类的 0-1 规划问题,如何对这些典型问题进行建模。在此基础上,才能调用 PuLP 函数进行求解。工具
欢迎关注 『Python小白的数学建模课 @ Youcans』,每周更新数模笔记
Python小白的数学建模课-01.新手必读
Python小白的数学建模课-02.数据导入
Python小白的数学建模课-03.线性规划
Python小白的数学建模课-04.整数规划
Python小白的数学建模课-05.0-1规划
Python数模笔记-PuLP库
Python数模笔记-StatsModels统计回归
Python数模笔记-Sklearn
Python数模笔记-NetworkX
Python数模笔记-模拟退火算法学习
规划问题的数学模型包括决策变量、约束条件和目标函数,围绕这三个要素均可能存在互斥的状况,从而导出不一样类型的0-1规划问题,其建模方法也有差异。优化
互斥的决策问题,是指决策方案、计划互斥,如决定投资项目、肯定投资场所、选择投产产品等。
例如,双十一的促销活动,淘宝、京东、拼多多要求店铺二选一,最多只能选择参加一家平台,不然可能会被封杀,这是典型的互斥决策问题。
背包问题就是经典的互斥决策问题。给定一组 n 个物品,每种物品 i 的价值为 v_i、重量/体积为 w_i,背包所能容纳的总重量/总容量为(B),如何选择其中若干种物品(每种物品选 0 个或 1 个),使得物品的总价值最高?
背包问题的建模方法以下:
定义决策变量为:
定义目标函数为:
不少应用问题均可以用上述的背包问题数学模型来表达,例如:
互斥的约束问题,是指具备多个互斥的约束条件,这些约束条件只有一个起做用。
例如,货物运输有车运或者船运两种运输方式可供选择,已知采用车运的约束条件和船运的约束条件,必须且只能选择其中一种运输方式。这两个约束条件互斥,有且只有一个起做用,这是能够引入一个 0-1变量来处理。
通常地,设有 m 个互斥的约束条件:
该类问题的建模方法,为了保证只有一个约束条件起做用,能够引入一个充分大的常数 M 和 m 个 0-1 变量表示约束是否起做用:
因而能够构造新的 m+1 个约束条件:
因为 M 足够大,新的约束条件就能保证只有 y_i=1 的约束条件起做用,而其它约束条件都不起做用。
固定费用问题,是指求解生产成本最小问题时,总成本包括固定成本和变更成本,而选择不一样生产方式会有不一样的固定成本,所以总成本与选择的生产方式有关。
固定费用问题,其实是互斥的目标函数问题,对于不一样的生产方式具备多个互斥的目标函数,但只有一个起做用。固定费用问题不能用通常的线性规划模型求解。
通常地,设有 m 种生产方式可供选择,采用第 j 种方式时的固定成本为 K_j、变更成本为 c_j、产量为 x_j,则采用各类生产方式的总成本分别为:
该类问题的建模方法,为了构造统一的目标函数,能够引入 m 个 0-1 变量 y_j 表示是否采用第 j 种生产方式:
因而能够构造新的目标函数和约束条件:
M 是一个充分大的常数。
分配 n 我的去作 n 件工做,每人只作一件工做,每件工做只有一我的作,已知每一个人作每件事的用时为c_ij,如何安排才能使花费的总时间最少。
引入 0-1 变量 x_ij:
指派问题的数学模型就能够描述为:
在此基础上,还能够衍生出新的问题:
目前 0-1 规划问题并无通用、高效、精确的求解方法,经常使用的方法或是针对特殊问题,或是近似方法。
须要特别指出的是,咱们在数学建模的学习中会遇到愈来愈多的问题都没有通用、高效、精确的求解方法,而是借助于计算机算法和程序来获得近似解。
求解 0-1 规划问题的思路,首先是穷举法,遍历决策变量的全部的组合,求出目标函数的最优值。随着问题规模的增大,变量的组合成指数增加,穷举法就不可能实现了。
隐枚举法是经过反复构造过滤条件,不断删除比当前解差的解集,并把优于当前最优解的结果做为新的最优解,再以新的最优解构造新的过滤条件,如此反复直到求出最优解。
隐枚举法经过过滤条件对穷举法进行改进,能够较快地求出最优解。分支定界法也是一种隐枚举法。
既然对较大规模问题没法穷举,没法得到数学意义上的最优解,那么另外一个思路就是随机搜索。因而大名鼎鼎、无所不能的蒙特卡洛法出场了。
蒙特卡洛法是一类随机方法的统称,也称随机取样法。顾名思义,蒙特卡洛法就是大量地对决策变量随机取值——若是能在知足约束条件的前提下随机取值就更好了,经过比较其目标函数值来不断得到更好的解,最后就能获得近似的最优解。
蒙特卡洛法的特色是,能够在随机采样上计算获得近似结果,采样越多,越近似最优解 ,但没法保证获得的结果是否是全局最优解。能够证实,在必定的计算量的状况下,蒙特卡洛法能够得到较好的满意解。
蒙特卡洛法的思想很简单,看起来算法也很简单,但实际上也涉及了深入的数学理论,算法理论与实践也都在不断的发展。
蒙特卡洛法不只能够处理几乎全部的决策问题、优化问题,并且在各类学科领域都获得了普遍的应用。这样的方法咱们固然不能错过,后文将专题进行讨论。
设计高效的启发式算法解决实际问题,是解决 0-1 规划问题的另外一个思路。
启发式算法一般是以问题为导向的,没有一个通用的框架,根据具体问题的特殊结构来识别启发性信息,构造启发式优化过程来高效地寻找近似最优解。
启发式算法得到的近似最优解,一般是局部最优解。并且,启发式算法的解须要借助其余方法来评估其质量,而且在实际应用中不能保证为各类算例稳定地生成接近全局最优的可行解。
原本不想在这里谈近似算法的,只是为了说明启发式算法并非近似算法。
近似算法与启发式算法是不一样的,近似算法每每经过巧妙的设计,获得的解是在全局最优解的某个邻域范围以内,或必定比例范围内。近似算法的解能够用严格的数学证实是“比较好”的,于是被认为是有保证的。
总结 0-1 规划的求解方法,就是没有通用、高效、精确的求解方法。
对于小白来讲,其实这样更简单,不要操心学习哪一种算法了,咱们仍是用 PuLP 工具包来求解。
不只继续用 PuLP 工具包,并且解题过程和编程步骤也与求解线性规划问题彻底一致。
下面咱们以一个简单的数学模型练习,来说解整个解题过程,而不只给出例程。
例题 1:
公司有 5 个项目被列入投资计划,各项目的投资额和预期投资收益以下表所示(万元):
项目 | A | B | C | D | E |
---|---|---|---|---|---|
投资额 | 210 | 300 | 100 | 130 | 260 |
投资收益 | 150 | 210 | 60 | 80 | 180 |
公司只有 600万元资金可用于投资,综合考虑各方面因素,须要保证:
(1)项目 A、B、C 中必须且只能有一项被选中;
(2)项目 C、D 中最多只能选中一项;
(3)选择项目 E 的前提是项目 A被选中。
如何在上述条件下,进行投资决策,使收益最大。
定义决策变量为:
定义目标函数为:
模型求解,用标准模型的优化算法对模型求解,获得优化结果。模型求解的编程步骤以下:
(0)导入 PuLP库函数
import pulp
(1)定义一个规划问题
InvestLP = pulp.LpProblem("Invest decision problem", sense=pulp.LpMaximize)
pulp.LpProblem 用来定义问题的构造函数。"InvestLP"是用户定义的问题名。
参数 sense 指定问题求目标函数的最小值/最大值 。本例求最大值,选择 “pulp.LpMaximize” 。
(2)定义决策变量
对于问题 1:
x1 = pulp.LpVariable('A', cat='Binary') # 定义 x1,A 项目 x2 = pulp.LpVariable('B', cat='Binary') # 定义 x2,B 项目 x3 = pulp.LpVariable('C', cat='Binary') # 定义 x3,C 项目 x4 = pulp.LpVariable('D', cat='Binary') # 定义 x4,D 项目 x5 = pulp.LpVariable('E', cat='Binary') # 定义 x5,E 项目
pulp.LpVariable 用来定义决策变量的函数。'x1'~'x5' 是用户定义的变量名。
参数 cat 用来设定变量类型,' Binary ' 表示0/1变量(用于0/1规划问题)。
(3)添加目标函数
InvestLP += (150*x1 + 210*x2 + 60*x3 + 80*x4 + 180*x5) # 设置目标函数 f(x)
(4)添加约束条件
InvestLP += (210*x1 + 300*x2 + 100*x3 + 130*x4 + 260*x5 <= 600) # 不等式约束 InvestLP += (x1 + x2 + x3 == 1) # 等式约束 InvestLP += (x3 + x4 <= 1) # 不等式约束 InvestLP += (x5 - x1 <= 0) # 不等式约束
添加约束条件使用 "问题名 += 约束条件表达式" 格式。
约束条件能够是等式约束或不等式约束,不等式约束能够是 小于等于 或 大于等于,分别使用关键字">="、"<="和"=="。
(5)求解
InvestLP.solve() print(InvestLP.name) # 输出求解状态 print("Status youcans:", pulp.LpStatus[InvestLP.status]) # 输出求解状态 for v in InvestLP.variables(): print(v.name, "=", v.varValue) # 输出每一个变量的最优值 print("Max f(x) =", pulp.value(InvestLP.objective)) # 输出最优解的目标函数值
solve() 是求解函数,能够对求解器、求解精度进行设置。
# mathmodel06_v1.py # Demo05 of mathematical modeling algorithm # Solving 0-1 binary programming with PuLP. # Copyright 2021 Youcans, XUPT # Crated:2021-06-02 # Python小白的数学建模课 @ Youcans import pulp # 导入 pulp 库 # 主程序 def main(): # 投资决策问题: # 公司现有 5个拟投资项目,根据投资额、投资收益和限制条件,问如何决策使收益最大。 """ 问题建模: 决策变量: x1~x5:0/1 变量,1 表示选择第 i 个项目, 0 表示不选择第 i 个项目 目标函数: max fx = 150*x1 + 210*x2 + 60*x3 + 80*x4 + 180*x5 约束条件: 210*x1 + 300*x2 + 100*x3 + 130*x4 + 260*x5 <= 600 x1 + x2 + x3 = 1 x3 + x4 <= 1 x5 <= x1 x1,...,x5 = 0, 1 """ InvestLP = pulp.LpProblem("Invest decision problem", sense=pulp.LpMaximize) # 定义问题,求最大值 x1 = pulp.LpVariable('A', cat='Binary') # 定义 x1,A 项目 x2 = pulp.LpVariable('B', cat='Binary') # 定义 x2,B 项目 x3 = pulp.LpVariable('C', cat='Binary') # 定义 x3,C 项目 x4 = pulp.LpVariable('D', cat='Binary') # 定义 x4,D 项目 x5 = pulp.LpVariable('E', cat='Binary') # 定义 x5,E 项目 InvestLP += (150*x1 + 210*x2 + 60*x3 + 80*x4 + 180*x5) # 设置目标函数 f(x) InvestLP += (210*x1 + 300*x2 + 100*x3 + 130*x4 + 260*x5 <= 600) # 不等式约束 InvestLP += (x1 + x2 + x3 == 1) # 等式约束 InvestLP += (x3 + x4 <= 1) # 不等式约束 InvestLP += (x5 - x1 <= 0) # 不等式约束 InvestLP.solve() # youcans print(InvestLP.name) # 输出求解状态 print("Status youcans:", pulp.LpStatus[InvestLP.status]) # 输出求解状态 for v in InvestLP.variables(): print(v.name, "=", v.varValue) # 输出每一个变量的最优值 print("Max f(x) =", pulp.value(InvestLP.objective)) # 输出最优解的目标函数值 return if __name__ == '__main__': # Copyright 2021 YouCans, XUPT main() # Python小白的数学建模课 @ Youcans
Welcome to the CBC MILP Solver Version: 2.9.0 Build Date: Feb 12 2015 Result - Optimal solution found Invest_decision_problem Status youcans: Optimal A = 1.0 B = 0.0 C = 0.0 D = 1.0 E = 1.0 Max f(x) = 410.0
从 0-1 规划模型的结果可知,选择 A、C、E 项目进行投资,能够知足限定条件并得到最大收益 410万元。
【本节完】
版权声明:
欢迎关注『Python小白的数学建模课 @ Youcans』 原创做品
原创做品,转载必须标注原文连接:。
Copyright 2021 Youcans, XUPT
Crated:2021-06-02
欢迎关注 『Python小白的数学建模课 @ Youcans』,每周更新数模笔记
Python小白的数学建模课-01.新手必读
Python小白的数学建模课-02.数据导入
Python小白的数学建模课-03.线性规划
Python小白的数学建模课-04.整数规划
Python小白的数学建模课-05.0-1规划
Python小白的数学建模课-06.固定费用问题
Python小白的数学建模课-07.选址问题
Python小白的数学建模课-09.微分方程模型
Python数模笔记-PuLP库
Python数模笔记-StatsModels统计回归
Python数模笔记-Sklearn
Python数模笔记-NetworkX
Python数模笔记-模拟退火算法