目录
1.题目
有N种物品和一个容量是V的背包。
第 i种物品最多有 si件,每件体积是 vi,价值是 wi。
求解将哪些物品装入背包,可使物品体积总和不超过背包容量,且价值总和最大。
输出最大价值。
输入格式
第一行两个整数,N,V用空格隔开,分别表示物品种数和背包容积。
接下来有 N行,每行三个整数 vi,wi,si,用空格隔开,分别表示第 i种物品的体积、价值和数量。
输出格式
输出一个整数,表示最大价值。
数据范围
0<N,V≤100
0<vi,wi,si≤100
输入样例
4 5
1 2 3
2 4 1
3 4 3
4 5 2
输出样例:
10
2.思路
不同:
与01背包相比,多重背包给出了每件物品的件数范围,而01背包中的物品只能使用一次
与完全背包相比,多重背包给出的物品件数是个给定范围,而完全背包中的物品可以无限使用
解决多重背包问题,我们可以将其转换为01背包来解决,多重背包中不是每个物品都给了一个件数范围吗?我们将总件数转化为1件,这便变成了01背包问题,像,题目中输入的第一个物品,它有3件,那我们便将其转化为3个第一个物品,但倘若一个物品它有1000件,那就意味这我们需要变成1000个这个物品,这将会造成时间上和空间上的浪费,对此我们可以使用二进制优化的方法,来缩减浪费
1 | |
2 | |
4 | |
8 | |
16 | |
32 | |
64 | |
128 | |
256 | |
489 |
我们每一个人都知道是512,但因为总件数是1000,除去前面的不够,所以此处的2的九次方相当于489。从这上面我们可以清晰的发现若不使用二进制我们需要拓展1000行(包含初始的一行),而使用二进制优化后只需要拓展10行。
对于该题,我们使用二进制优化后,将会变成
编号 | 体积 | 价值 |
1 | 1 | 2 |
2 | 2 | 4 |
3 | 2 | 4 |
4 | 3 | 4 |
5 | 6 | 8 |
6 | 4 | 5 |
7 | 4 | 5 |
在扩展完形成新的列表之后,求最大价值的方法与01背包使用dp滚动数组求最大价值的方法一致,若对01背包使用dp滚动数组求最大价值的方法不了解,可跳转到01背包问题详解和python代码进行学习。
3.代码
tempv列表:
[1, 2, 2, 3, 6, 4, 4]
tempw列表:
[2, 4, 4, 4, 8, 5, 5]
我们可以很清晰的发现这与前面列的表格如出一辙
python代码:
n,v=map(int,input().split())
bag=[]
for i in range(n):
bag.append(list(map(int,input().split())))
tempv=[]
tempw=[]
newn=0#用newn来表示新的列表的长度
for i in range(n):#使用二进制优化的方法创建一个新的体积和价值列表
k = 1
while(k<=bag[i][2]):
tempv.append(k*bag[i][0])
tempw.append(k*bag[i][1])
bag[i][2]=bag[i][2]-k
k = k * 2#二进制,所以间隔为2
newn+=1
if(bag[i][2]!=0):#此情况是上述2的九次方的情况,确保剩余的加进去
tempv.append(bag[i][2] * bag[i][0])
tempw.append(bag[i][2] * bag[i][1])
newn=newn+1
def fun(newn,v,tempv,tempw):#使用新的列表来求最大价值,其方法与01背包使用一维dp数组的方法一致
dp=[0 for i in range(v+1)]
for i in range(1,newn+1):
for j in range(v,-1,-1):
if(j>=tempv[i-1]):
dp[j]=max(dp[j],dp[j-tempv[i-1]]+tempw[i-1])
else:
dp[j]=dp[j]
print(dp[-1])
fun(newn,v,tempv,tempw)