AcWing-混合背包问题(思路+python代码)

1.题目

有 N𝑁 种物品和一个容量是 V𝑉 的背包。

物品一共有三类:

  • 第一类物品只能用1次(01背包);
  • 第二类物品可以用无限次(完全背包);
  • 第三类物品最多只能用 si𝑠𝑖 次(多重背包);

每种体积是 vi𝑣𝑖,价值是 wi𝑤𝑖。

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

输入格式

第一行两个整数,N,V𝑁,𝑉,用空格隔开,分别表示物品种数和背包容积。

接下来有 N𝑁 行,每行三个整数 vi,wi,si𝑣𝑖,𝑤𝑖,𝑠𝑖,用空格隔开,分别表示第 i𝑖 种物品的体积、价值和数量。

  • si=−1𝑠𝑖=−1 表示第 i𝑖 种物品只能用1次;
  • si=0𝑠𝑖=0 表示第 i𝑖 种物品可以用无限次;
  • si>0𝑠𝑖>0 表示第 i𝑖 种物品可以使用 si𝑠𝑖 次;

输出格式

输出一个整数,表示最大价值。

数据范围

0<N,V≤10000<𝑁,𝑉≤1000
0<vi,wi≤10000<𝑣𝑖,𝑤𝑖≤1000
−1≤si≤1000−1≤𝑠𝑖≤1000

输入样例

4 5
1 2 -1
2 4 1
3 4 0
4 5 2

输出样例:

8

2.思路

本题需要用到完全背包和01背包问题的知识,如若有不了解或有遗忘,可跳转到下面页面进行学习:

01背包问题

完全背包问题

对于混合背包,我们可以清晰的看出这是三个背包问题的整合,而为了解决这个问题,我们我们可以将其中的01背包问题和完全背包问题均转化为多重背包问题,然后使用多重背包问题的二进制优化来解决该题。

01背包转换为多重背包,毋庸置疑只需要在tempv,tempw(存放优化后的体积和价值的列表)两个列表中分别加上对应的物品,因为01背包中的物品只有一件,也就是只能使用一次,所以直接加入就行

完全背包转换为多重背包,因为完全背包中的物品可以使用无数次,也就相当于有无数件物品,但我们知道,背包它是有总体积的,虽然物品可以一直使用,但它由于背包总体积的限制,导致它的范围上限变成了:v/物品体积,这样完全背包就转换成了多重背包问题。然后使用二进制优化的写法把其添加到优化后的列表中

全部转换完成后,此时也相当于完成了二进制优化,之后便可以使用一维dp滚动列表求出最大价值

3.代码

 python代码:

n,v=map(int,input().split())#输入n,v
bag=[]
for i in range(n):
    bag.append(list(map(int,input().split())))#将体积,价值,类型全部放入bag中
tempv=[]#用于存放二进制优化后的体积
tempw=[]#用于存放二进制优化后的价值
newn=0#用于统计优化后总共的物品
for i in range(n):
    if(bag[i][2]==-1):#01背包
        tempv.append(bag[i][0])
        tempw.append(bag[i][1])
        newn=newn+1
    elif(bag[i][2]==0):#完全背包
        k = 1
        x=v//bag[i][0]#因为总体积的缘故,所以虽然其为完全背包的类型,终还是有上限
        while(k<=x):
            tempv.append(k*bag[i][0])
            tempw.append(k*bag[i][1])
            x=x-k
            k=k*2
            newn=newn+1
        if(x!=0):
            tempv.append(x*bag[i][0])
            tempw.append(x*bag[i][1])
            newn = newn + 1
    elif(bag[i][2]>0):#多重背包
        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
            newn = newn + 1
        if (bag[i][2] != 0):
            tempv.append(bag[i][2] * bag[i][0])
            tempw.append(bag[i][2] * bag[i][1])
            newn = newn + 1
dp=[0 for i in range(v+1)]
def fun(newn,tempv,tempw,v):#一维滚动dp列表求最大价值
    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,tempv,tempw,v)

  • 11
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
背包问题和0-1背包问题都是动态规划问题,它们的主要区别在于背包问题中的物品可以取任意数量,而0-1背包问题中的物品只能取0或1。 以下是背包问题和0-1背包问题Python代码实现: **背包问题** ```python def knapsack(items, capacity): n = len(items) dp = [ * (capacity + 1) for _ in range(n + 1)] for i in range(1, n + 1): weight, value = items[i - 1] for j in range(capacity, -1, -1): if j >= weight: dp[i][j] = max(dp[i - 1][j], dp[i - 1][j] return dp[n][capacity] ``` 在这个代码中,items是一个列表,包含一系列物品及其重量和价值。capacity是背包的容量。函数返回的是在给定容量下可以获得的最大价值。 **0-1背包问题** ```python def knapsack_0_1(items, capacity): n = len(items) dp = [ * (capacity + 1) for _ in range(n + 1)] for i in range(1, n + 1): weight, value = items[i - 1] for j in range(capacity, -1, -1): if j >= weight: dp[i][j] = max(dp[i - 1][j - weight]) if dp[i - 1][j - weight] else 0 else: dp[i][j] = dp[i][j - weight] if dp[i][j - weight] else float('inf') # 若没有选择的选项,取无穷大(即为取值为零)作为代表。 dp[i][j] = min(dp[i][j], dp[i][j-weight]) if dp[i][j] > capacity else dp[i][j] # 最后如果总的容量大于给定的容量,就不能选之前的选项,那么最后的方案应等于剩余容量的情况下的最优方案。 return dp[n][capacity] # 这个点对应的是选择的最后一个物品时能获得的最大价值。因为是从后向前计算,最后一个物品的价值必定小于其单独的值。如果该物品值过大(超出总容量),就考虑替换之前的选项(且最优的替换方式)而不是完全装入背包中。最后,选取一个方案的最大值就是我们的结果。 ``` 这段代码中的物品同样需要给出其重量和价值,返回的是在给定容量下可以获得的最大价值,但是只能选择0或1,不能选择多个物品。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值