题目:有四个物品,书包总容量为8,背包最多能装入价值为多少的物品
物品编号 | 1 | 2 | 3 | 4 |
---|---|---|---|---|
物品体积 | 2 | 3 | 4 | 5 |
物品价值 | 3 | 4 | 5 | 6 |
0-1背包:物品件数为1
完全背包:物品件数为有限件
如果装不下当前物品,那么n个物品的最住组合和前n-1个物品的最住组合是一样的。
如果装得下当前物品。
假设1:装当前物品,在给当前物品预留了相应空间的情况下,前n-1个物品的最佳组合加上当前物品的价值就是总价值。
假设2:不装当前物品,那么前n个物品的最佳组合和前n-1个物品的最佳组合是一样的。
选取假设1和假设2中较大的价值,为当前最佳组合的价值。
回溯:从表的右下角开始回溯,如果发现前n个物品最佳组合的价值和前n-1个物品最佳组合的价值一样,说明第n个物品没有被装入。
否则,第n个物品被装入。
# 01 背包
import numpy as np
weight = [2,3,4,5] # 物品重量
price = [3,4,5,6] # 物品价值
weight_most = 10
def fullbag(weight, price, weight_most): # return max value
num = len(weight) # 获取物品总量
weight.insert(0, 0) # 不存在第0个物品,故插入一个0
price.insert(0, 0) # 同上
bag = np.zeros((num + 1, weight_most + 1), dtype=np.int32) # 使用numpy快速建立数组,下标从零开始
# bag0 = [0 for j in range(weight_most+1)] #不导入np三方库
# bag = [bag0 for i in range(num+1)]
for i in range(1, num + 1): # 这俩循环的取值为行与列,每件物品进行循环
for j in range(1, weight_most + 1): # 从轻的开始拿
if weight[i] <= j:
bag[i][j] = max(bag[i - 1][j - weight[i]] + price[i], bag[i - 1][j])
else:
bag[i][j] = bag[i - 1][j]
print(bag)
# 回溯计算应该装入的体积
op_volume = []
j = weight_most
for i in reversed(range(1,num+1)):
if bag[i][j] != bag[i-1][j]:
op_volume.append(weight[i])
j=j-weight[i]
print("装入的体积",op_volume)
return bag[-1, -1]
if __name__ == '__main__':
result = fullbag(weight, price, weight_most)
print("装入的价值",result)
# 完全背包
import numpy as np
weight = [2,3,4,5] # 物品重量
price = [3,4,5,6] # 物品价值
weight_most = 8
def fullbag(weight, price, weight_most): # return max value
num = len(weight) # 获取物品总量
weight.insert(0, 0) # 不存在第0个物品,故插入一个0
price.insert(0, 0) # 同上
bag = np.zeros((num + 1, weight_most + 1), dtype=np.int32) # 使用numpy快速建立数组,下标从零开始
knum = np.zeros((num + 1, weight_most + 1), dtype=np.int32)
# bag0 = [0 for j in range(weight_most+1)] #不导入np三方库
# bag = [bag0 for i in range(num+1)]
for i in range(1, num + 1): # 这俩循环的取值为行与列,每件物品进行循环
for j in range(1, weight_most + 1): # 从轻的开始拿
if weight[i] <= j:
k=0
while (k * weight[i] <= j):
bag[i][j] = max(bag[i][j - k * weight[i]] + k * price[i], bag[i - 1][j])
if bag[i][j - k * weight[i]] + k * price[i] > bag[i - 1][j]:
knum[i][j] = k
k=k+1
else:
bag[i][j] = bag[i - 1][j]
print(bag)
# 回溯计算应该装入的体积
j = weight_most
for i in reversed(range(1, num + 1)):
if bag[i][j] != bag[i - 1][j]:
if (knum[i][j]>0):
print("装入物品{}共{}件".format(i,knum[i][j]))
j=j-knum[i][j]*weight[i]
return bag[-1, -1]
if __name__ == '__main__':
result = fullbag(weight, price, weight_most)
print("装入的价值", result)
优化如上k值
# 完全背包优化
import numpy as np
weight = [2,3,4,5] # 物品重量
price = [3,4,5,6] # 物品价值
weight_most = 8
def fullbag(weight, price, weight_most): # return max value
num = len(weight) # 获取物品总量
weight.insert(0, 0) # 不存在第0个物品,故插入一个0
price.insert(0, 0) # 同上
bag = np.zeros((num + 1, weight_most + 1), dtype=np.int32) # 使用numpy快速建立数组,下标从零开始
# bag0 = [0 for j in range(weight_most+1)] #不导入np三方库
# bag = [bag0 for i in range(num+1)]
for i in range(1, num + 1): # 这俩循环的取值为行与列,每件物品进行循环
for j in range(1, weight_most + 1): # 从轻的开始拿
if weight[i] <= j:
bag[i][j] = max(bag[i][j - weight[i]] + price[i], bag[i - 1][j])
else:
bag[i][j] = bag[i - 1][j]
print(bag)
return bag[-1, -1]
# 回溯计算应该装入的体积
j = weight_most
k=1
for i in reversed(range(1,num+1)):
if bag[i][j] != bag[i-1][j]:
print("装入物品{}共{}件".format(i, knum[i][j]))
j = j - knum[i][j] * weight[i]
print("装入的体积",op_volume)
return bag[-1, -1]
if __name__ == '__main__':
result = fullbag(weight, price, weight_most)
print("装入的价值",result)