本范例主要是通过分支界限法解决著名的0/1背包客问题
问题描述:
有件商品,记为。每件商品的重量和价值分别为和;
其中,
现在有一个背包,可以容纳的最大重量为。
问该背包可以包含的最大价值是多少?
基本思路:
本问题是一个典型的排列组合问题,只要能满足总重量小于背包的容量的所有组合中,找到那个价值最大的组合;
每一件商品都有2种选择,要么包含该商品,要么不包含该商品
因此总共有种组合方式。当N很大时,如果尝试每一种组合方式,将会使得计算量变得非常大。如下图所示
上图中每一个小圆圈都代表一个节点,对于每一个小节点,都拥有两个分支,两种选择,即包不包含某一个商品,这既是分支界限法种分支的由来。而界限是指我们做每一个选择时,我们先提前预估一下加入做了该选择,可能出现的最优或最差情况,即所谓的上界和下界
比如我们从零开始,我们算一下最大价值是多少?按照贪婪算法思想,我们商品已由单位重量价值进行了从大到小的排列
那么开始最大可能价值就是A,B,C全部包含,D商品部分包含, 由于可以包含部分商品,因此本价值提供了可能最大价值的上限。
假如包含商品A,则上限还是250,假如不包含商品A,则上限计算应是B,C的全部价值加D部分价值,应该是
分支界限法的思想就是不断选择那个预测值最大的路,像上述包含商品A预测值大于不包含商品A的情况,因此,我们暂时选择包含商品A,下一步就可以考虑是否包含商品B,计算方法类似
更换路线条件:
按照上述方法就为沿着一条路线不断前进且在岔路口选择是否包含某一商品提供了一种判断方法,那么什么情况得更换线路呢?
- 重量超标的情况,本例中,假如每一条路线重量超过了10,则该路走不通了,必须切换到当前预测价值最大的那条线路。
- 预测值下降严重,已经小于另一条线路上的预测值,这是应更换到那条预测值大的线路上,也就是说时刻走预测值最大的那条线路
结束条件:
-
每一件商品都考虑到了,如何此时还是最优的情况,那么这条线路就一定是最优的情况,如本例中就是包含商品A,B,C,不包含商品D,最大价值是235
python代码
"""
Created on Mon Jan 7 21:57:42 2019
@author: WAY
"""
from copy import copy,deepcopy
class Item:
def __init__(self,w,v):
self.w = w
self.v = v
self.r = v/w
def __lt__(self,other):
return self.r<other.r
class Node:
def __init__(self):
self.layer = -1
self.info=[]
self.optimum_value = -1
self.total_weight=0
def __lt__(self,other):
return self.optimum_value<other.optimum_value
class Knapsack:
def __init__(self,N,maxweight):
self.N=N
self.items = []
self.max_weight = maxweight
self.max_value = 0
self.quene = []
def add_item(self,item):
self.items.append(item)
def sort_item(self):
self.items.sort()
self.items.reverse()
def calculate_matrix_value(self,node):
weight = 0
value = 0
for i in node.info:
weight += i.w
value += i.v
if weight>self.max_weight:
node.optimum_value = -1
return
node.total_weight=weight
for j in range(node.layer+1,self.N):
if weight + self.items[j].w <= self.max_weight:
weight += self.items[j].w
value += self.items[j].v
else:
value += self.items[j].r*(self.max_weight-weight)
break
node.optimum_value = value
def knapsack(self):
node = Node()
self.calculate_matrix_value(node)
self.max_value = node.optimum_value
self.quene.append(node)
panduan = 0
while self.quene:
if panduan == 0:
node = self.quene.pop()
panduan=1
node_L = deepcopy(node)
node_L.layer += 1
node_L.info.append(self.items[node_L.layer])
self.calculate_matrix_value(node_L)
if node_L.optimum_value>0 and node_L.optimum_value <=self.max_value:
self.quene.append(node_L)
node_R = deepcopy(node)
node_R.layer += 1
self.calculate_matrix_value(node_R)
if node_R.optimum_value>0 and node_R.optimum_value <=self.max_value:
self.quene.append(node_R)
self.quene.sort()
node = self.quene.pop()
if node.layer == 3:
break
return node
def main():
item1 = Item(2,40)
item2 = Item(3.14,50)
item3 = Item(1.98,100)
item4 = Item(5,95)
k = Knapsack(4,10)
k.add_item(item1)
k.add_item(item2)
k.add_item(item3)
k.add_item(item4)
k.sort_item()
nn = k.knapsack()
print(nn.optimum_value)
print(nn.total_weight)
for i in nn.info:
print(i.w)
if __name__ == "__main__":
main()
网友评论