您的位置:首页 > 其它

算法0-1背包问题:

2014-04-17 17:50 337 查看
参考博客:
http://blog.csdn.net/livelylittlefish/article/details/2186206 http://www.cnblogs.com/Anker/archive/2013/05/04/3059070.html
#coding=utf-8
def domatch(things):
"""
把每个重量的最大值保存到weight_value_list
weight_value_list:重量:保存在经过所有索引后的(重量,价值)键值对
things:物品,由(重量,价值)构成
"""
inthings=things[:]#内部使用的物品
inthings.insert(0,(0,0))#插入初始物品(0,0)
weight_value_list=dict()
length=len(things) #列表长度
oldresult=[(0,0,[])]#字典 索引:[(重量,价值,索引集合)]
for index,(newweight,newvalue) in enumerate(inthings):
if index>0:
previndex=index-1
newresult=[]#对当前索引的键值对初始化
for weightindex,(weight,value,index_list) in enumerate(oldresult):#取出上一个索引的键值,然后再进行操作

#weight_value_list[index].extend([(weight,value),(weight+newweight,value+newvalue)])
newresult.append((weight,value,index_list))
index_list2=index_list[:]
index_list2.append(index)
node2=(weight+newweight,value+newvalue,index_list2)
newresult.append(node2)
del oldresult[:]
oldresult=newresult[:]
weight_value_dict=dict()#存放重量:[最大价值,索引列表]的键值对
alltuples=newresult
for (weight,value,final_list) in  alltuples:
if weight not in weight_value_dict:#如果重量没有在weight_value_dict中
weight_value_dict[weight]=[value,final_list]
elif weight_value_dict[weight][0]<value:#如果weight_value_dict中相对重量的价值小于value
weight_value_dict[weight]=[value,final_list]
return weight_value_dict

#return weight_value_dict
def findmaxvalue(inweight,weight_value_dict):
"""
查找最大价值
"""
return weight_value_dict[inweight]#l输出的结果是[最大价值,索引列表]
if __name__=='__main__':
weight_str='2 3 4 7'
ws=[ int(item) for item in weight_str .split(' ') if item]
value_str='1 3 5 9 '
vs=[int(item) for item in  value_str.split(' ') if item]
things=zip(ws,vs)#(重量,价值)
weight_value_dict=domatch(things)
print findmaxvalue(10,weight_value_dict)
#print things


结果:



但是发现有错误啊。。

但这段数据测试的时候

weight_str='2 2 6 5 4'

ws=[ int(item) for item in weight_str .split(' ') if item]

value_str='6 3 5 4 6'

我取到的最大值是的4而不是的5.这就是问题所在了。

这是因为,我是在最后对每个重量取得最大价值,

按理而言,应该在遍历things的每一个元素的时候,就对oldresult做一下修理,使得对于每个重量一定取到小于或者等于该重量的价值的最大值。

最后代码如下:

#coding=utf-8
def domatch(things):
"""
把每个重量的最大值保存到weight_value_list
weight_value_list:重量:保存在经过所有索引后的(重量,价值)键值对
things:物品,由(重量,价值)构成
"""
inthings=things[:]#内部使用的物品
inthings.insert(0,(0,0))#插入初始物品(0,0)
weight_value_list=dict()
length=len(things) #列表长度
oldresult=[(0,0,[])]#字典 索引:[(重量,价值,索引集合)]
for index,(newweight,newvalue) in enumerate(inthings):
if index>0:

newresult=[]#对当前索引的键值对初始化
for weightindex,(weight,value,index_list) in enumerate(oldresult):#取出上一个索引的键值,然后再进行操作

#weight_value_list[index].extend([(weight,value),(weight+newweight,value+newvalue)])
newresult.append((weight,value,index_list))
index_list2=index_list[:]
index_list2.append(index)
node2=(weight+newweight,value+newvalue,index_list2)
newresult.append(node2)
del oldresult[:]
oldresult=newresult[:]
#对oldresult作整理,使得对于每个重量的价值取到的一定是小于或者等于该重量的最大价值
weight_value_dict=dict()#存放重量:[最大价值,索引列表]的键值对
alltuples=newresult
for (fweight,fvalue,final_list) in  alltuples:
#如果重量没有在weight_value_dict中
if fweight not in weight_value_dict:
weight_value_dict[fweight]=(fvalue,final_list)
#如果weight_value_dict中相对重量的价值小于value
elif weight_value_dict[fweight][0]<fvalue:
weight_value_dict[fweight]=(fvalue,final_list)
oldresult=[]
for dweight,(dvalue,dlist) in weight_value_dict.iteritems():
oldresult.append((dweight,dvalue,dlist))
oldresult.sort( key=lambda x:x[0])#按照重量排序
for sortedindex,(comweight,comvalue,comli) in enumerate(oldresult):
if sortedindex>0:
previndex=sortedindex-1
if oldresult[previndex][1]>comvalue:
oldresult[sortedindex]=(comweight,)+tuple(oldresult[previndex][1:])

weight_value_dict=dict()#存放重量:[最大价值,索引列表]的键值对
alltuples=newresult
for (weight,value,final_list) in  alltuples:
if weight not in weight_value_dict:#如果重量没有在weight_value_dict中
weight_value_dict[weight]=[value,final_list]
elif weight_value_dict[weight][0]<value:#如果weight_value_dict中相对重量的价值小于value
weight_value_dict[weight]=[value,final_list]
return weight_value_dict

#return weight_value_dict
def findmaxvalue(inweight,weight_value_dict):
"""
查找最大价值
"""

return weight_value_dict[inweight]#l输出的结果是[最大价值,索引列表]
if __name__=='__main__':
weight_str='12 16 24 7 29 32 5 43 31 1'
ws=[ int(item) for item in weight_str .split(' ') if item]
value_str='11 16 15 9 24 25 3 32 41 7'
vs=[int(item) for item in  value_str.split(' ') if item]
things=zip(ws,vs)#(重量,价值)
weight_value_dict=domatch(things)
print findmaxvalue(105,weight_value_dict)
#print things


输出结果是:



但是我在用递归法写的时候却出现了问题:

#coding=utf-8
def findmaxvalue(weight,things):
inthings=things[:]
inthings.insert(0,(0,0))
lenofthings=len(inthings)
return findmaxvaluebylen(weight,inthings,lenofthings-1,lenofthings-1)
known=dict()
def findmaxvaluebylen(weight,inthings,index,maxindex):
"""
weight:要求得最大价值时的重量
inthings:已经被处理过的列表
index:在遍历inthings时的索引
maxindex:inthings的最大索引
"""
if index in known:
return known[index]
else:
if index==0:
reobject=(weight,0,[])#重量,价值,索引列表
known[index]=reobject
return reobject
else:
nowweight,nowvalue=inthings[index]
if nowweight>weight:
reobject=findmaxvaluebylen(weight,inthings,index-1,maxindex)
known[index]=reobject
return reobject
else:
reobject1=findmaxvaluebylen(weight,inthings,index-1,maxindex)#当前节点不包含在结果中
newweight=weight-nowweight
reobject2=findmaxvaluebylen(newweight,inthings,index-1,maxindex)#当前节点包含在结果里
ele_list=reobject2[2][:]
ele_list.append(index)
reobject2=(weight,reobject2[1]+nowvalue,ele_list)
reobject=reobject1
if reobject1[1]<reobject2[1]:
reobject=reobject2
known[index]=reobject
return reobject
if __name__=='__main__':
weight_str='12 16 24 7 29 32 5 43 31 1'
ws=[ int(item) for item in weight_str .split(' ') if item]
value_str='11 16 15 9 24 25 3 32 41 7'

vs=[int(item) for item in  value_str.split(' ') if item]
things=zip(ws,vs)#(重量,价值)
things.sort()
print findmaxvalue(105,things)
#print things


结果却是这个样子:



跟之前的对不上啊,这是怎么回事啊。。为什么会这个样子呢。。真坑啊。

应该是我子结构错了,改下子结构:

结果如下:

#coding=utf-8
def findmaxvalue(weight,things):
inthings=things[:]
inthings.insert(0,(0,0))
lenofthings=len(inthings)
return findmaxvaluebylen(weight,inthings,lenofthings-1,lenofthings-1)
known={0:{0:(0,[])}}
def findmaxvaluebylen(weight,inthings,index,maxindex):
"""
weight:要求得最大价值时的重量
inthings:已经被处理过的列表
index:在遍历inthings时的索引
maxindex:inthings的最大索引
"""
if index in known:
tempdict=known[index]
if weight in tempdict:
return tempdict[weight]
if index==0:
reobject=(0,[])
known[index][weight]=reobject
return reobject
nowweight,nowvalue=inthings[index]
reobject=findmaxvaluebylen(weight,inthings,index-1,maxindex)
#发现在index==3 and weight==5的时候,reobject=None
if nowweight>weight:
fixdictbyobject(known,index,weight,reobject)
known[index][weight]=reobject

return reobject
else:
newweight=weight-nowweight
reobject2=findmaxvaluebylen(newweight,inthings,index-1,maxindex)
ele_list=reobject2[1][:]
ele_list.append(index)
reobject2=(reobject2[0]+nowvalue,ele_list)
if reobject[0]<reobject2[0]:
reobject=reobject2
fixdictbyobject(known,index,weight,reobject)
known[index][weight]=reobject
return reobject
def fixdictbyobject(known_dict,index,comweight,reobject):
"""
整理 known_dict[index]
使得所有重量大于comweight的价值都大于或者等于reobject的价值,
"""
if  index not in known_dict:
known_dict[index]=dict()
return
else:
for tempweight,(tempvalue,templist) in known_dict[index].iteritems():
if tempweight>comweight and tempvalue<reobject[0]:
known_dict[index][tempweight]=reobject[:]
return
if __name__=='__main__':
weight_str='12 16 24 7 29 32 5 43 31 1'
ws=[ int(item) for item in weight_str .split(' ') if item]
value_str='11 16 15 9 24 25 3 32 41 7'

vs=[int(item) for item in  value_str.split(' ') if item]
things=zip(ws,vs)#(重量,价值)
things.sort()
print findmaxvalue(105,things)
#print things
但是结果还是有问题啊

最大价值没错,但是索引列表错了啊。这是怎么会事呢



这个为什么是[1,2,3,4,5,8,9]呢,蛋疼啊。

知道为什么会这个样子了。。原来是我对things.sort()进行了排序。。。注销掉那一句就行了。

最终代码为:

#coding=utf-8
def findmaxvalue(weight,things):
inthings=things[:]
inthings.insert(0,(0,0))
lenofthings=len(inthings)
return findmaxvaluebylen(weight,inthings,lenofthings-1,lenofthings-1)
known={0:{0:(0,[])}}
def findmaxvaluebylen(weight,inthings,index,maxindex):
"""
weight:要求得最大价值时的重量
inthings:已经被处理过的列表
index:在遍历inthings时的索引
maxindex:inthings的最大索引
"""
if index in known:
tempdict=known[index]
if weight in tempdict:
return tempdict[weight]
if index==0:
reobject=(0,[])
known[index][weight]=reobject
return reobject
nowweight,nowvalue=inthings[index]
reobject=findmaxvaluebylen(weight,inthings,index-1,maxindex)
if nowweight>weight:
fixdictbyobject(known,index,weight,reobject)
known[index][weight]=reobject

return reobject
else:
newweight=weight-nowweight
reobject2=findmaxvaluebylen(newweight,inthings,index-1,maxindex)
ele_list=reobject2[1][:]
ele_list.append(index)
reobject2=(reobject2[0]+nowvalue,ele_list)
if reobject[0]<reobject2[0]:
reobject=reobject2
fixdictbyobject(known,index,weight,reobject)
known[index][weight]=reobject
return reobject
def fixdictbyobject(known_dict,index,comweight,reobject):
"""
整理 known_dict[index]
使得所有重量大于comweight的价值都大于或者等于reobject的价值,
"""
if  index not in known_dict:
known_dict[index]=dict()
return
else:
for tempweight,(tempvalue,templist) in known_dict[index].iteritems():
if tempweight>comweight and tempvalue<reobject[0]:
known_dict[index][tempweight]=reobject[:]
return
if __name__=='__main__':
weight_str='12 16 24 7 29 32 5 43 31 1'
ws=[ int(item) for item in weight_str .split(' ') if item]
value_str='11 16 15 9 24 25 3 32 41 7'

vs=[int(item) for item in  value_str.split(' ') if item]
things=zip(ws,vs)#(重量,价值)
#things.sort()
print findmaxvalue(105,things)
#print things


运行的结果为:



终于把0-1背包问题解决了,。。弄了两天了。。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: