目录
1.题目
有 N件物品和一个容量是 V的背包。每件物品只能使用一次。
第 i𝑖 件物品的体积是 vi,价值是 wi。
求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
输出 最优选法的方案数。注意答案可能很大,请输出答案模+7的结果。
输入格式
第一行两个整数,N,V用空格隔开,分别表示物品数量和背包容积。
接下来有 N行,每行两个整数 vi,wi用空格隔开,分别表示第 i𝑖 件物品的体积和价值。
输出格式
输出一个整数,表示 方案数 模 109+7109+7 的结果。
数据范围
0<N,V≤1000
0<vi,wi≤1000
输入样例
4 5
1 2
2 4
3 4
4 6
输出样例:
2
2.思路
对于这题的解法与01背包问题有关,若有小伙伴对01背包问题有所遗忘,可跳转到01背包问题进行复习
由前面01背包问题的知识可知,我们dp二维数组的列表如下图所示:
选几个物品\体积 | 0 | 1 | 2 | 3 | 4 | 5 |
0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | 0 | 2 | 2 | 2 | 2 | 2 |
2 | 0 | 2 | 4 | 6 | 6 | 6 |
3 | 0 | 2 | 4 | 6 | 6 | 8 |
4 | 0 | 2 | 4 | 6 | 6 | 8 |
但我们需要求的是最大价值对应的方案数是多少,同理也用列出一个表格
选几个物品\体积 | 0 | 1 | 2 | 3 | 4 | 5 |
0 | 1 | 1 | 1 | 1 | 1 | 1 |
1 | 1 | 1 | 1 | 1 | 1 | 1 |
2 | 1 | 1 | 1 | 1 | 1 | 1 |
3 | 1 | 1 | 1 | 1 | 2 | 1 |
4 | 1 | 1 | 1 | 1 | 3 | 2 |
为什么会呈现表上的形式呢?接下来,我们进行详细分析:
对于体积为0的时候,无论选几个物品,背包中都放不下任何物品,所以相应的方案数也就是1:不放任何物品
选0个物品:
无论体积是多少,都只有一种方案就是没有放入任何东西
选1个物品:
当体积为1时,由上面的那个dp列表,我们发现,此时放入了第一个物品,也就是一种方案,之后,体积为2,3,4,5无论为体积为多少,都只有一种方案,那就是放入第一个物品
选2个物品:
当体积为1时,还是只有一个方案:放入第一个物品,当体积为2时,通过dp列表,我们发现,此时,放入的是第二个物品,所以只有一种方案,就是只放入第二个物品,当体积为3时,通过dp列表我们发现此时的最大价值是6,也就是放入了第一个物品和第二个物品,但方案数还是1,因为当最大价值为6时,只能放入第一个物品和第二个物品,同样当体积为4和5时,还是只有一种方案:放入第一个物品和第二个物品
选3个物品:
当体积为1,2时,体积小于第三个物品的体积,不选第三个物品,那方案数还是和上一行的方案数一致,也就是只有一种方案,当体积为3时,因为此时选第三件物品的价值是4,而不选第三件物品的价值是6,所以不选第三件物品,方案数与上一行的方案数一致,当体积为4时,此时最大价值是6,但通过观察我们发现,选第一个物品和第二个物品时,最大价值为6,而选第三件物品和第一件物品的价值也是6,所以此时的方案数为2,当体积为5时,最大价值时8,只有一种方案就是选第二个物品和第三个物品
选4个物品:
当体积为1,2,3时,背包的体积都小于第四件物品的体积也就是说不选第四件物品,所以方案数于上一行也就是只选三件物品的方案数一致,当体积为4时,此时的最大价值是6,此时背包的体积于第四件物品的体积一致,考虑选不选第四件物品,当不选四件物品的时候,最大价值是6,方案数继承上一行的方案数也就是2,当选第四件物品的时候,最大价值是6,方案数为只选第四件物品,所以当体积为4的时候,方案数=上一行的方案数+选第四件物品的方案数=3,当体积为5时,考虑选不选第四件物品,当不选时最大价值为8,方案数为1,选第四件物品的最大价值为8,方案数为1,所以总方案数为2。
总结
通过上面的逐行分析,我们可以发现,可用01背包的方法列出背包方案数的列表,所以我们可以列出下面的方程组:
s[i][j](i从1到n+1):方案数的dp列表
1.当背包体积<物品体积时(相当于不选第i件物品):
s[i][j]=s[i-1][j]
2.当背包体积>=物品体积时:
bag[i][0]:体积
bag[i][1]:价值
1.dp[i-1][j]>dp[i-1][j-bag[i-1][0]]+bag[i-1][1](此公式在01背包中有讲):
相当于不选第i件物品
s[i][j]=s[i-1][j]
2.dp[i-1][j-bag[i-1][0]]+bag[i-1][1]>dp[i-1][j]:
相当于选了第i件之后判断对应的方案数,因为多选了件物品只会导致体积变小但并不会导致方案数变化,比如上面表格中选三个物品体积为5的时候,当选了第三物品后,会导致体积变为5-3=2,所以只需要找到上一行体积为2的方案数,便是选了第三件物品的方案数。
s[i][j]=s[i-1][j-bag[i-1][0]]
3.dp[i-1][j-bag[i-1][0]]+bag[i-1][1]==dp[i-1][j]:
这时便需要分别考虑选第i物品的方案数和不选第i件物品的方案数,然后两者相加即可
s[i][j]=s[i-1][j-bag[i-1][0]]+s[i-1][j]
3.代码
n,v=map(int,input().split())
bag=[]
for i in range(n):
bag.append(list(map(int,input().split())))
dp=[[0 for i in range(v+1)]for j in range(n+1)]
s=[[1 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):
if(j>=bag[i-1][0]):
if(dp[i-1][j]>dp[i-1][j-bag[i-1][0]]+bag[i-1][1]):
dp[i][j]=dp[i-1][j]
s[i][j]=s[i-1][j]
elif(dp[i-1][j]<dp[i-1][j-bag[i-1][0]]+bag[i-1][1]):
dp[i][j]=dp[i-1][j-bag[i-1][0]]+bag[i-1][1]
s[i][j]=s[i-1][j-bag[i-1][0]]
elif(dp[i-1][j]==dp[i-1][j-bag[i-1][0]]+bag[i-1][1]):
dp[i][j]=dp[i-1][j]
s[i][j]=s[i-1][j-bag[i-1][0]]+s[i-1][j]
elif(j<bag[i-1][0]):
dp[i][j]=dp[i-1][j]
s[i][j]=s[i-1][j]
print(s[-1][-1]%(10**9+7))#注意题目要求