本题力扣上没有,是刷的卡码网第52题52. 携带研究材料感兴趣的小伙伴可以去刷一下,是ACM模式。
题目:
题目描述:
小明是一位科学家,他需要参加一场重要的国际科学大会,以展示自己的最新研究成果。他需要带一些研究材料,但是他的行李箱空间有限。这些研究材料包括实验设备、文献资料和实验样本等等,它们各自占据不同的空间,并且具有不同的价值。
小明的行李空间为 N,问小明应该如何抉择,才能携带最大价值的研究材料,每种研究材料可以选择无数次,并且可以重复选择。
输入描述:
第一行包含两个整数,N,V,分别表示研究材料的种类和行李空间
接下来包含 N 行,每行两个整数 wi 和 vi,代表第 i 种研究材料的重量和价值
输出描述:
输出一个整数,表示最大价值。
输入示例:
4 5
1 2
2 4
3 4
4 5
输出示例:
10
提示信息:
第一种材料选择五次,可以达到最大值。
数据范围:
1 <= N <= 10000;
1 <= V <= 10000;
1 <= wi, vi <= 10^9.
思路:
完全背包
有N件物品和一个最多能背重量为W的背包。第i件物品的重量是weight[i],得到的价值是value[i] 。每件物品都有无限个(也就是可以放入背包多次),求解将哪些物品装入背包里物品价值总和最大。
完全背包和01背包问题唯一不同的地方就是,每种物品有无限件。
在下面的讲解中,依然举这个例子:
背包最大重量为4。
物品为:
重量 | 价值 | |
---|---|---|
物品0 | 1 | 15 |
物品1 | 3 | 20 |
物品2 | 4 | 30 |
每件商品都有无限个!
问背包能背的物品最大价值是多少?
01背包和完全背包唯一不同就是体现在遍历顺序上,所以本篇博客就不去做动规五部曲了,我们直接针对遍历顺序经行分析!(要先掌握01背包)
01背包问题详细请见动态规划:01背包问题(二)
首先再回顾一下01背包的核心代码:
for i in range(bag_nums): # 遍历每个物品
for j in range(bag_weight, weight[i] - 1, -1): # 从后往前遍历背包重量
dp[j] = max(dp[j], dp[j - weight[i]] + value[i]) # 更新当前背包重量对应的最大价值
我们知道01背包内层循环是从大到小遍历,为了保证每个物品仅被添加一次。
而完全背包的物品是可以添加多次的,所以要从小到大去遍历,即:
for i in range(bag_nums):
# 从weight[i]到bag_weight遍历,更新dp数组
for j in range(weight[i], bag_weight + 1):
# 更新dp[j]的值
dp[j] = max(dp[j], dp[j - weight[i]] + value[i])
具体原因01背包中都有讲过
还有一个很重要的问题,为什么遍历物品在外层循环,遍历背包容量在内层循环?
01背包中二维dp数组的两个for遍历的先后循序是可以颠倒了,一维dp数组的两个for循环先后循序一定是先遍历物品,再遍历背包容量。
在完全背包中,对于一维dp数组来说,其实两个for循环嵌套顺序是无所谓的!
因为dp[j] 是根据 下标j之前所对应的dp[j]计算出来的。 只要保证下标j之前的dp[j]都是经过计算的就可以了。
遍历物品在外层循环,遍历背包容量在内层循环,状态如图:
遍历背包容量在外层循环,遍历物品在内层循环,状态如图:
看了这两个图,大家就会理解,完全背包中,两个for循环的先后循序,都不影响计算dp[j]所需要的值(这个值就是下标j之前所对应的dp[j])。
注意,这里先后循环顺序可以颠倒指的是纯完全背包问题,如果结合具体题目可能就不能颠倒。
代码及详细注释:
# 读取输入
N = [int(x) for x in input().split()]
bag_nums = N[0] # 物品的数量
bag_weight = N[1] # 背包的容量
weight = [] # 物品的重量
value = [] # 物品的价值
# 读取每个物品的重量和价值
for _ in range(bag_nums):
a, b = map(int, input().split())
weight.append(a)
value.append(b)
# 创建一个长度为bag_weight+1的数组dp,用于记录背包容量为j时的最大总价值
dp = [0] * (bag_weight + 1)
# 遍历每个物品
for i in range(bag_nums):
# 从weight[i]到bag_weight遍历,更新dp数组
for j in range(weight[i], bag_weight + 1):
# 更新dp[j]的值
dp[j] = max(dp[j], dp[j - weight[i]] + value[i])
# 输出背包容量为bag_weight时的最大总价值
print(dp[bag_weight])