分枝定界法解0/1背包问题
分枝定界法解0/1背包问题
关键词:分支定界、0-1背包
分枝定界法简介
分枝定界法按照树形结构来组织解空间,展开节点后,有两种策略:
策略一、把节点加入 FIFO 队列当中;
策略二、把节点加入到堆中,按照最小消耗或者最大消耗来选择下一个展开节点。
感悟
分枝定界法是一类能确保搜索到全部可行解的解空间的一类方法。得到全部的解以后,再由后续程序自行觉得。
分枝定界法与回溯法的区别
分枝定界法 | 回溯法 |
---|---|
搜索解空间的方法是 BFS(广度优先) | 搜索解空间的方法是 DFS(深度优先) |
算法搜索的解空间大,消耗的内存多 | 算法搜索的解空间大,消耗的内存少 |
0/1背包问题
有背包问题形式化描述如下:
\[n = 3 \\
weights = [20, 15, 15] \\
values = [40, 25, 25] \\
constraint = 30
\]
用分枝定界法,代码实现如下:
# -*- coding:utf8 -*-
import copy
from collections import deque
# 用分枝定界法解决0/1背包问题
def brunch_bound(w, p, c):
plan = list()
buffer = deque([[copy.copy(w), [], []]]) # [waiting, explored, values]
while len(buffer):
cur = buffer.popleft()
for i in range(0, len(cur[0])):
weight = cur[0][i]
n = copy.deepcopy(cur)
n[0].remove(weight)
n[1].append(weight)
n[2].append(p[i])
if sum(n[1]) > c:
continue # overloaded
buffer.append(copy.deepcopy(n))
plan.append(cur)
return plan
if __name__ == '__main__':
w = [20, 15, 15]
p = [40, 25, 25]
c = 30
plan = brunch_bound(w,p,c)
l = sorted(plan, key=lambda x:sum(x[2]), reverse=True) # l[0] is the most value plan
for e in l:
print(e)
输出:
[[20], [15, 15], [25, 25]] #显然,这是最优方案
[[20], [15, 15], [25, 25]]
[[15, 15], [20], [40]]
[[20, 15], [15], [25]]
[[20, 15], [15], [25]]
[[20, 15, 15], [], []]
解释
copy.copy 是浅拷贝,子对象不会被拷贝
copy.deepcopy 是深拷贝
智慧在街市上呼喊,在宽阔处发声。