给定一个宝物列表treasureList = [{‘w’: 2,‘v’: 3}, {‘w’: 3,‘v’: 4}, …]
注意:每样宝物只有1个。
给定包裹最多承重maxWeight > 0,实现一个函数,根据以上条件得到最高总价值以及对应的宝物
参数:宝物列表treasureList,背包最大承重maxWeight
返回值:最大总价值maxValue,选取的宝物列表chosenList(格式同treasureList)
maxValue(i,w)代表在最大承重w前提下,在前i个宝物中取得的最大的价值,有如下对应关系:
解释:
1、当没有宝物或者最大承重为0,也即i=0或者w=0时,maxValue(i,w)=0
2、当第i件宝物的重量本身就大于最大承重时,即当weight(i)>w时,maxValue(i,w)=maxValue(i-1,w)
3、当第i件宝物重量小于最大承重时,需要考虑“取该宝物”和“不取该宝物”两种情况
4、代码回溯问题:注意:不能在代码中使用chosenList.append()
def dpMuseumThief(treasureList, maxWeight):
maxValue = 0
chosenList = []
#小技巧:使得tr重点 所有宝物都是从1开始编号
tr=[None]+treasureList
#记录表格
m={(i,w):[0,None] for i in range(len(tr)) for w in range(maxWeight+1)}
#逐个填写
for i in range(1,len(tr)):
for w in range(1,maxWeight+1):
#第i件宝物重量大于最大承重,不能装进去
if tr[i]['w']>w:
m[i,w][0]=m[i-1,w][0]
#能装进去,要考虑是否要装
else:
if m[i-1,w][0]>m[i-1,w-tr[i]['w']][0]+tr[i]['v']:
m[i,w][0]=m[i-1,w][0]
else:
m[i,w][0]=m[i-1,w-tr[i]['w']][0]+tr[i]['v']
m[i,w][1]=tr[i]
maxValue=m[i,w][0]
while w>0:#回溯这一路走下来一共添加了几件宝物
if m[i,w][1] is not None:
chosenList.insert(0,m[i,w][1])#保持添加顺序不变
w=w-m[i,w][1]['w']
i=i-1
return maxValue, chosenList
def dpMuseumThief(treasureList, maxWeight):
maxValue = 0
choosenList = []
#代码开始
# 大盗最大承重和可能拿走的宝物最多件数
max_w, max_num = maxWeight, len(treasureList)
#小技巧,使得宝物从1开始计数
treasureList=[None]+treasureList
# 初始化maxvalue和treasure_used,记录在当前可选宝物范围中,大盗可拿走的最大总价值及对应宝物
mtv = [[0 for i in range(max_w+1)] for j in range(max_num+1)]
treasure_used= [[False for p in range(max_w+1)] for q in range(max_num+1)]
# 循环添加宝物至“大盗可选清单”
for i in range(1,max_num+1):
need_w,get_v = treasureList[i]['w'],treasureList[i]['v'] # 添加的宝物的重量和价值
for j in range(1,max_w+1):
if j<need_w: # 如果当前物品重量大于背包容量
mtv[i][j]=mtv[i-1][j] # 和这个物品不存在时一样
else:
# 如果可以放,需要进一步决策:大于上一次选择的最佳方案则更新mtv[i][j]
treasure_used[i][j] = (mtv[i - 1][j - need_w] + get_v > mtv[i - 1][j])
mtv[i][j]=max(mtv[i-1][j-need_w]+ get_v ,mtv[i-1][j])
# 记录在mtv[i][j]时是否选择了放入第i-1件宝物
maxValue=mtv[max_num][max_w] # 回溯打印编号
#以下是回溯得到取得宝物的列表
num=max_num
w=max_w
s = ""
while num > 0:
if treasure_used[num][w]:
choosenList.append(treasureList[num])
w = w - treasureList[num]['w']
num = num - 1 # 处理依据 mtv[i-1][j-need_w]+ get_v
else:
num = num - 1 # 处理依据 mtv[i-1][j]
# 代码结束
return maxValue, choosenList
# 检验
print("=========== 1 博物馆大盗问题 ============")
treasureList = [[{'w':2, 'v':3}, {'w':3, 'v':4}, {'w':4, 'v':8}, {'w':5, 'v':8}, {'w':9, 'v':10}]]
treasureList.append([{'w':1, 'v':2}, {'w':2, 'v':2}, {'w':2, 'v':3}, {'w':4, 'v':5}, {'w':4, 'v':6}, {'w':4, 'v':7}, {'w':5, 'v':7},
{'w':5, 'v':8}, {'w':6, 'v':8}, {'w':6, 'v':10}, {'w':7, 'v':10}, {'w':7, 'v':12}, {'w':8, 'v':12}, {'w':8, 'v':13}, {'w':9, 'v':14}, {'w':9, 'v':16}])
treasureList.append([{'w':1, 'v':2}, {'w':2, 'v':2}, {'w':2, 'v':3}, {'w':3, 'v':4}, {'w':3, 'v':5}, {'w':4, 'v':6}, {'w':4, 'v':7},
{'w':5, 'v':7}, {'w':5, 'v':8}, {'w':6, 'v':8}, {'w':6, 'v':10}, {'w':7, 'v':11}, {'w':7, 'v':12}, {'w':8, 'v':13},
{'w':8, 'v':14}, {'w':9, 'v':15}, {'w':9, 'v':16}, {'w':9, 'v':17}, {'w':10, 'v':17}, {'w':10, 'v':18}, {'w':11, 'v':18}])
treasureList.append([{'w':1, 'v':2}, {'w':2, 'v':2}, {'w':2, 'v':3}, {'w':3, 'v':4}, {'w':3, 'v':5}, {'w':4, 'v':5}, {'w':4, 'v':6},
{'w':5, 'v':6}, {'w':5, 'v':7}, {'w':6, 'v':8}, {'w':6, 'v':9}, {'w':7, 'v':10}, {'w':7, 'v':11}, {'w':8, 'v':12},
{'w':8, 'v':13}, {'w':9, 'v':14}, {'w':9, 'v':15}, {'w':9, 'v':16}, {'w':10, 'v':16}, {'w':10, 'v':17}, {'w':11, 'v':18},
{'w': 12, 'v': 18}, {'w': 12, 'v': 19}, {'w': 13, 'v': 20}, {'w': 13, 'v': 21}, {'w': 14, 'v': 21}, {'w': 14, 'v': 22}])
treasureList.append([{'w':1, 'v':2}, {'w':2, 'v':2}, {'w':2, 'v':3}, {'w':3, 'v':4}, {'w':3, 'v':5}, {'w':4, 'v':5}, {'w':4, 'v':6},
{'w':5, 'v':6}, {'w':5, 'v':7}, {'w':6, 'v':8}, {'w':6, 'v':9}, {'w':7, 'v':9}, {'w':7, 'v':10}, {'w':8, 'v':11},
{'w':8, 'v':12}, {'w':9, 'v':13}, {'w':9, 'v':14}, {'w':9, 'v':15}, {'w':10, 'v':16}, {'w':10, 'v':17}, {'w':11, 'v':18},
{'w': 11, 'v': 19}, {'w': 12, 'v': 20}, {'w': 13, 'v': 20}, {'w': 13, 'v': 21}, {'w': 14, 'v': 21}, {'w': 14, 'v': 22},
{'w': 14, 'v': 23}, {'w': 15, 'v': 24},{'w': 15, 'v': 25}, {'w': 16, 'v': 26},{'w': 17, 'v': 27}, {'w': 18, 'v': 28}])
maxWeightList = [20, 50, 80, 100, 150]
for i in range(len(treasureList)):
maxValue, choosenList = dpMuseumThief(treasureList[i], maxWeightList[i])
print(maxValue)
print(choosenList)
解释:
treasureList
作为一个全局变量并进行了赋值使用,因而原来的含有5组不同宝物列表的大列表更名为treasure
def MaxValue(i, w):
if i==0 or w==0:
MaxValueMap[(i,w)]=[0,None]
return 0
else:
if treasureList[i]['w']>w:#装不下第i个
#已经缓存过了
if (i-1,w) in MaxValueMap:
MaxValueMap[(i,w)]=MaxValueMap[(i-1,w)]
return MaxValueMap[(i-1,w)][0]
#没有缓存过
return MaxValue(i-1,w)
else:#装得下第i个
if (i-1,w) in MaxValueMap:#已经缓存过了
Value1=MaxValueMap[(i-1,w)][0]
else:#没有缓存过
Value1=MaxValue(i-1,w)
if (i-1,w-treasureList[i]['w']) in MaxValueMap:#已经缓存过了
Value2=MaxValueMap[(i-1,w-treasureList[i]['w'])][0]+treasureList[i]['v']
else:#没有缓存过
Value2=MaxValue(i-1,w-treasureList[i]['w'])+treasureList[i]['v']
#比较,权衡
if Value2>Value1:
MaxValueMap[(i,w)]=[Value2,treasureList[i]]
return Value2
else:
MaxValueMap[(i,w)]=[Value1,None]
return Value1
def printChosenList(MaxValueMap,max_num, max_w):#回溯得到宝物
i,w=max_num, max_w
chosenList=[]
while w>0:#由于MaxValueMap
if (i,w)in MaxValueMap and MaxValueMap[(i,w)][1] is not None:
chosenList.append(MaxValueMap[(i,w)][1])
w=w-MaxValueMap[(i,w)][1]['w']
i=i-1
print(chosenList)
# 检验
print("=========== 1 博物馆大盗问题 ============")
treasure = [[{'w':2, 'v':3}, {'w':3, 'v':4}, {'w':4, 'v':8}, {'w':5, 'v':8}, {'w':9, 'v':10}]]
treasure.append([{'w':1, 'v':2}, {'w':2, 'v':2}, {'w':2, 'v':3}, {'w':4, 'v':5}, {'w':4, 'v':6}, {'w':4, 'v':7}, {'w':5, 'v':7},
{'w':5, 'v':8}, {'w':6, 'v':8}, {'w':6, 'v':10}, {'w':7, 'v':10}, {'w':7, 'v':12}, {'w':8, 'v':12}, {'w':8, 'v':13}, {'w':9, 'v':14}, {'w':9, 'v':16}])
treasure.append([{'w':1, 'v':2}, {'w':2, 'v':2}, {'w':2, 'v':3}, {'w':3, 'v':4}, {'w':3, 'v':5}, {'w':4, 'v':6}, {'w':4, 'v':7},
{'w':5, 'v':7}, {'w':5, 'v':8}, {'w':6, 'v':8}, {'w':6, 'v':10}, {'w':7, 'v':11}, {'w':7, 'v':12}, {'w':8, 'v':13},
{'w':8, 'v':14}, {'w':9, 'v':15}, {'w':9, 'v':16}, {'w':9, 'v':17}, {'w':10, 'v':17}, {'w':10, 'v':18}, {'w':11, 'v':18}])
treasure.append([{'w':1, 'v':2}, {'w':2, 'v':2}, {'w':2, 'v':3}, {'w':3, 'v':4}, {'w':3, 'v':5}, {'w':4, 'v':5}, {'w':4, 'v':6},
{'w':5, 'v':6}, {'w':5, 'v':7}, {'w':6, 'v':8}, {'w':6, 'v':9}, {'w':7, 'v':10}, {'w':7, 'v':11}, {'w':8, 'v':12},
{'w':8, 'v':13}, {'w':9, 'v':14}, {'w':9, 'v':15}, {'w':9, 'v':16}, {'w':10, 'v':16}, {'w':10, 'v':17}, {'w':11, 'v':18},
{'w': 12, 'v': 18}, {'w': 12, 'v': 19}, {'w': 13, 'v': 20}, {'w': 13, 'v': 21}, {'w': 14, 'v': 21}, {'w': 14, 'v': 22}])
treasure.append([{'w':1, 'v':2}, {'w':2, 'v':2}, {'w':2, 'v':3}, {'w':3, 'v':4}, {'w':3, 'v':5}, {'w':4, 'v':5}, {'w':4, 'v':6},
{'w':5, 'v':6}, {'w':5, 'v':7}, {'w':6, 'v':8}, {'w':6, 'v':9}, {'w':7, 'v':9}, {'w':7, 'v':10}, {'w':8, 'v':11},
{'w':8, 'v':12}, {'w':9, 'v':13}, {'w':9, 'v':14}, {'w':9, 'v':15}, {'w':10, 'v':16}, {'w':10, 'v':17}, {'w':11, 'v':18},
{'w': 11, 'v': 19}, {'w': 12, 'v': 20}, {'w': 13, 'v': 20}, {'w': 13, 'v': 21}, {'w': 14, 'v': 21}, {'w': 14, 'v': 22},
{'w': 14, 'v': 23}, {'w': 15, 'v': 24},{'w': 15, 'v': 25}, {'w': 16, 'v': 26},{'w': 17, 'v': 27}, {'w': 18, 'v': 28}])
maxWeightList = [20, 50, 80, 100, 150]
for k in range(len(treasure)):
MaxValueMap={}
treasureList=[None]+treasure[k]
max_w, max_num = maxWeightList[k], len(treasureList)-1
print(MaxValue(max_num, max_w))
printChosenList(MaxValueMap,max_num, max_w)
# 可有多种取法,以下只给出一种符合条件的宝物列表
# 29
# [{'w':2, 'v':3}, {'w':4, 'v':8}, {'w':5, 'v':8}, {'w':9, 'v':10}]
# 83
# [{'w': 1, 'v': 2}, {'w': 2, 'v': 3}, {'w': 4, 'v': 7}, {'w': 5, 'v': 8}, {'w': 6, 'v': 10}, {'w': 7, 'v': 12}, {'w': 8, 'v': 12}, {'w': 8, 'v': 13}, {'w': 9, 'v': 16}]
# 139
# [{'w': 1, 'v': 2}, {'w': 3, 'v': 5}, {'w': 4, 'v': 6}, {'w': 4, 'v': 7}, {'w': 6, 'v': 10}, {'w': 7, 'v': 12}, {'w': 8, 'v': 14}, {'w': 9, 'v': 15}, {'w': 9, 'v': 16}, {'w': 9, 'v': 17}, {'w': 10, 'v': 17}, {'w': 10, 'v': 18}]
# 164
# [{'w': 1, 'v': 2}, {'w': 3, 'v': 5}, {'w': 8, 'v': 13}, {'w': 9, 'v': 15}, {'w': 9, 'v': 16}, {'w': 10, 'v': 16}, {'w': 10, 'v': 17}, {'w': 11, 'v': 18}, {'w': 12, 'v': 19}, {'w': 13, 'v': 21}, {'w': 14, 'v': 22}]
# 246
# [{'w': 1, 'v': 2}, {'w': 3, 'v': 4}, {'w': 3, 'v': 5}, {'w': 9, 'v': 15}, {'w': 10, 'v': 17}, {'w': 11, 'v': 18}, {'w': 11, 'v': 19}, {'w': 12, 'v': 20}, {'w': 13, 'v': 21}, {'w': 14, 'v': 23}, {'w': 15, 'v': 24}, {'w': 15, 'v': 25}, {'w': 16, 'v': 26}, {'w': 17, 'v': 27}]