背包问题求方案数(思路+python代码)

目录

1.题目

2.思路

3.代码


1.题目

有 N件物品和一个容量是 V的背包。每件物品只能使用一次。

第 i𝑖 件物品的体积是 vi,价值是 wi。

求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。

输出 最优选法的方案数。注意答案可能很大,请输出答案模10^{9}+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二维数组的列表如下图所示:

dp列表
选几个物品\体积012345
0000000
1022222
2024666
3024668
4024668

但我们需要求的是最大价值对应的方案数是多少,同理也用列出一个表格

方案数列表
选几个物品\体积012345
0111111
1111111
2111111
3111121
4111132

为什么会呈现表上的形式呢?接下来,我们进行详细分析:

对于体积为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))#注意题目要求

  • 24
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值