建模实战|第三期:解决背包问题与装箱问题-python调用Ortools求解器
背包问题(Knapsack problem):容器数量是固定的,每个容器有自己的最大容量,而需要分配的物件有各自的价值,我们的目标是让装入容器的物体的总价值最大,并不要求所有物体都装入。装箱问题( Bin-packing problem):容器数量不固定,每个容器容量是相同的,有自己的最大容量,我们的目标是用最少的容器来存放所有的物件。装箱问题也可以分为多种情况,如完全装箱问题、不完全装箱问题、一
1.背包问题与装箱问题
背包问题(Knapsack problem):容器数量是固定的,每个容器有自己的最大容量,而需要分配的物件有各自的价值,我们的目标是让装入容器的物体的总价值最大,并不要求所有物体都装入。背包问题有如下分类:
问题分类 | 容器数量 | 约束条件 |
---|---|---|
0-1背包问题 | 1个 | 1个 |
多背包问题 | 多个 | 1个但每个背包对应不同的约束 |
多维背包问题 | 1个 | 多个 |
装箱问题( Bin-packing problem):容器数量不固定,每个容器容量是相同的,有自己的最大容量,我们的目标是用最少的容器来存放所有的物件。装箱问题也可以分为多种情况,如完全装箱问题、不完全装箱问题、一维装箱问题和二维装箱问题等。
2.背包问题建模
2.1 0-1背包问题建模
实例:见OR-Tools官网题目
50个物品被装入一个箱子。每个物品都有一个值(物品上的数字)和一个重量(与物品的面积大致成比例)。背包的容量被为850,目标是找到一组能使总价值最大化而又不超过容量的物品。
python调用ortools求解:
from ortools.linear_solver import pywraplp
values = [
360, 83, 59, 130, 431, 67, 230, 52, 93, 125, 670, 892, 600, 38, 48, 147,
78, 256, 63, 17, 120, 164, 432, 35, 92, 110, 22, 42, 50, 323, 514, 28,
87, 73, 78, 15, 26, 78, 210, 36, 85, 189, 274, 43, 33, 10, 19, 389, 276,
312
]
weights = [
7, 0, 30, 22, 80, 94, 11, 81, 70, 64, 59, 18, 0, 36, 3, 8, 15, 42, 9, 0,
42, 47, 52, 32, 26, 48, 55, 6, 29, 84, 2, 4, 18, 56, 7, 29, 93, 44, 71,
3, 86, 66, 31, 65, 0, 79, 20, 65, 52, 13
]
W = 850 # 背包容量
num_items = len(weights) # 物件数量 J
# 建模
solver = pywraplp.Solver.CreateSolver("SCIP")
# 决策变量
x = {}
for j in range(num_items):
x[j] = solver.IntVar(0, 1, f"x{j}")
# 约束条件
cn_terms = []
for j in range(num_items):
cn_terms.append(weights[j] * x[j])
solver.Add(solver.Sum(cn_terms) <= W)
# 目标函数
objective_terms = []
for j in range(num_items):
objective_terms.append(values[j] * x[j])
solver.Maximize(solver.Sum(objective_terms))
status = solver.Solve()
if status == pywraplp.Solver.OPTIMAL or status == pywraplp.Solver.FEASIBLE:
print(f"Total value = {solver.Objective().Value()}")
total_weight = 0
picked_items = []
for j in range(num_items):
if x[j].solution_value() > 0.5:
total_weight += weights[j]
picked_items.append(j)
print(f"total weight={total_weight}")
print(f"装入了背包的物品:{picked_items}")
else:
print("No solution found.")
结果输出:
Total value = 7534.0
total weight=850
装入了背包的物品:[0, 1, 3, 4, 6, 10, 11, 12, 14, 15, 16, 17, 18, 19, 21, 22, 24, 27, 28, 29, 30, 31, 32, 34, 38, 39, 41, 42, 44, 47, 48, 49]
2.2 多背包问题建模
约束2:限制每个物件只能装入一个背包
python调用ortools求解:
from ortools.linear_solver import pywraplp
weights = [48, 30, 42, 36, 36, 48, 42, 42, 36, 24, 30, 30, 42, 36, 36] w
values = [10, 30, 25, 50, 35, 30, 15, 40, 30, 35, 45, 10, 20, 30, 25] v
W = [100, 100, 100, 100, 100] # 5个背包的容量 W
num_items = len(weights) # 物件数量 J
num_knapsacks = len(W) # 背包数量 I
# 建模
solver = pywraplp.Solver.CreateSolver("SCIP")
# 决策变量
x = {}
for i in range(num_knapsacks):
for j in range(num_items):
x[i,j] = solver.IntVar(0, 1, f"x{i}{j}")
# 约束条件
# 目标函数
结果输出:
Total value = 395.0
背包0的total weight=96
装入了背包0的物品是:[1, 10, 14]
背包1的total weight=192
装入了背包1的物品是:[8, 9, 13]
背包2的total weight=276
装入了背包2的物品是:[7, 12]
背包3的total weight=348
装入了背包3的物品是:[3, 4]
背包4的total weight=438
装入了背包4的物品是:[2, 5]
2.3 多维背包问题
python调用ortools求解:
from ortools.linear_solver import pywraplp
# ==========测试==========
knapsack = {"weight": 600, "volume": 600}
values = [1898, 440, 22507, 270, 14148, 3100, 4650, 30800, 615, 4975, 1160, 4225, 510, 11880, 479, 440, 490, 330, 110,
560, 24355, 2885, 11748, 4550, 750, 3720, 1950, 10500]
weights = [45, 5, 85, 150, 65, 95, 30, 12, 170, 20, 40, 25, 20, 3, 7, 25, 12, 22, 25, 9, 165, 2, 85, 15, 9, 2, 4, 100]
volumes = [30, 20, 125, 5, 80, 25, 35, 73, 12, 15, 15, 40, 5, 10, 10, 12, 10, 9, 10, 20, 60, 40, 50, 36, 49, 40, 19,
150]
dimension_items = {
"weight": weights,
"volume": volumes
}
solver = pywraplp.Solver.CreateSolver("SCIP")
num_dimensions = len(dimension_items)
num_items = len(values)
# 0-1决策变量
x = {}
for j in range(num_items):
x[j] = solver.IntVar(0, 1, f'x{j}')
# 约束条件
# 目标函数
结果输出:
Total cost = 140668.0
背包—放入的物品: [2, 4, 6, 7, 9, 10, 11, 13, 20, 22, 23, 25, 26]
3.完全装箱问题建模
约束2:限制每个物件只能装入一个箱子
python调用ortools求解:
from ortools.linear_solver import pywraplp
weights = [48, 30, 19, 36, 36, 27, 42, 42, 36, 24, 30] # w_j
num_items = len(weights) # 物件集合J
num_bins = num_items # 箱子集合I
W = 100 # 箱子的容量
solver = pywraplp.Solver.CreateSolver("SCIP")
# 初始化决策变量
# Variables
# x[i, j] = 1 if item i is packed in bin j.
x = {}
for i in range(num_bins):
for j in range(num_items):
x[i, j] = solver.IntVar(0, 1, f"x{i}{j}")
# y[j] = 1 if bin j is used.
y = {}
for i in range(num_bins):
y[i] = solver.IntVar(0, 1, f"y{i}")
# 约束条件
# 目标函数
结果输出:
num of bins = 4.0
箱子0-装入物品:[0, 1, 2]
箱子0-总重量:97
箱子1-装入物品:[3, 4, 5]
箱子1-总重量:99
箱子2-装入物品:[6, 7]
箱子2-总重量:84
箱子3-装入物品:[8, 9, 10]
箱子3-总重量:90
4.相关阅读
OR-Tools:2-包装问题,箱包问题(bin packing)
这里有个疑问,相关阅读中用的CBC求解器和本文中采用的SCIP求解出来的结果不同,待研究
相关视频会在后续发布,欢迎关注我的bilibili:无形忍者的个人空间-无形忍者个人主页-哔哩哔哩视频
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)