1.题目
有N组物品和一个容量是V的背包。
每组物品有若干个,同一组内的物品最多只能选一个。
每件物品的体积是 vij,价值是 wij,其中 i是组号,j是组内编号。
求解将哪些物品装入背包,可使物品总体积不超过背包容量,且总价值最大。
输出最大价值。
输入格式
第一行有两个整数 N,V用空格隔开,分别表示物品组数和背包容量。
接下来有 N组数据:
- 每组数据第一行有一个整数 Si,表示第 i个物品组的物品数量;
- 每组数据接下来有 Si行,每行有两个整数 vij,wij用空格隔开,分别表示第 i个物品组的第 j个物品的体积和价值;
输出格式
输出一个整数,表示最大价值。
数据范围
0<N,V≤100
0<Si≤100
0<vij,wij≤100
输入样例
3 5
2
1 2
2 4
1
3 4
1
4 5
输出样例:
8
2.思路
对于该题,跟01背包问题有着很大的相似程度,但与01背包问题不同的是,它又进行了进一步的分组,也就是说相当于由原来的二维列表变成了三维列表,本题需要用到01背包的知识,对01背包不清晰的小伙伴可以点击01背包问题进行学习。
对比:
01背包问题中,我们在列状态方程时需要考虑的关键是:是否放入第i件物品,也就是判断是放入第i个物品的价值大,还是不放入第i个物品的价值大
多重背包问题中,因为它分组的缘故,我们需要考虑是否放入第i个组,以及假如放入第i个组,那放入第i个组中哪一个物品的价值大,也就是说,对于分组背包问题,我们需要判断,是放入第i个组中第k个物品的价值大,还是不放入第i个组的价值大
关键:
对于本题的关键是列出背包的三维数组以及通过三个循环如何表示状态转移方程
优化:
对于本题,我们还是可以仿照01背包的样式,对多重背包使用一维滚动dp数组进行优化,缩小空间复杂度,方法同01背包转换一维滚动dp数组的方法一致,已经在01背包问题中写的很详细了,这里便不过多阐述
3.代码
二维dp数组:
[0, 0, 0, 0, 0, 0]
[0, 2, 4, 4, 4, 4]
[0, 2, 4, 4, 6, 8]
[0, 2, 4, 4, 6, 8]
二维dp数组python代码:
n, v = map(int, input().split())#n是有几组,v是背包体积
bags = []
s=[]
for i in range(n):
s.append(int(input()))
bag = []
for j in range(s[i]):
tv, tw = map(int, input().split())
bag.append([tv, tw])
bags.append(bag)
dp = [[0 for i in range(v+1)] for j in range(n+1)]
for i in range(1,n+1):
for j in range(v+1):
dp[i][j]=dp[i-1][j]#指不放这一组的最大价值
for k in range(s[i-1]):#这个循环用来判断放入组中的哪一个价值更大
if(j>=bags[i-1][k][0]):
dp[i][j]=max(dp[i][j],dp[i-1][j-bags[i-1][k][0]]+bags[i-1][k][1])
print(dp[-1][-1])
一维滚动dp数组python代码:
n, v = map(int, input().split())#n是有几组,v是背包体积
bags = []
s=[]
for i in range(n):
s.append(int(input()))
bag = []
for j in range(s[i]):
tv, tw = map(int, input().split())
bag.append([tv, tw])
bags.append(bag)
dp=[0 for i in range(v+1)]
for i in range(1,n+1):
for j in range(v,-1,-1):
for k in range(s[i-1]):
if(j>=bags[i-1][k][0]):
dp[j]=max(dp[j],dp[j-bags[i-1][k][0]]+bags[i-1][k][1])
print(dp[-1])