AcWing 6 多重背包问题 III 题解(动态规划—DP—背包问题)

博客介绍了如何用动态规划和单调队列解决多重背包问题。通过对传统DP方程的调整,将二维数组优化为一维,并通过维护单调队列找到每个容量下的最大价值。博主lys分享了具体的公式和算法实现思路。
摘要由CSDN通过智能技术生成

一共 n 类物品,背包的容量是 m

每类物品的体积为v, 价值为w,个数为s

我们先来回顾一下传统的dp方程

dp[i][j] 表示将前 i 种物品放入容量为 j 的背包中所得到的最大价值
dp[i][j] = max(不放入物品 i,放入1个物品 i,放入2个物品 i, … , 放入k个物品 i)
这里 k 要满足:k <= s, j - k*v >= 0

不放物品 i = dp[i-1][j]
放k个物品 i = dp[i-1][j - kv] + kw

dp[i][j] = max(dp[i-1][j], dp[i-1][j-v] + w, dp[i-1][j-2v] + 2w,…,dp[i-1][j-kv] + kw)

实际上我们并不需要二维的dp数组,适当的调整循环条件,我们可以重复利用dp数组来保存上一轮的信息

我们令 dp[j] 表示容量为j的情况下,获得的最大价值
那么,针对每一类物品 i ,我们都更新一下 dp[m] --> dp[0] 的值,最后 dp[m] 就是一个全局最优值

dp[m] = max(dp[m], dp[m-v] + w, dp[m-2v] + 2w, dp[m-3v] + 3w, …)

接下来,我们把 dp[0] --> dp[m] 写成下面这种形式

dp[0], dp[v], dp[2v], dp[3v], … , dp[kv]
dp[1], dp[v+1],dp[2
v+1], dp[3v+1], … ,dp[kv+1]
dp[2], dp[v+2], dp[2v+2],dp[3v+2], … , dp[kv+2]

dp[j], dp[v+j], dp[2
v+j], dp[3v+j],… , dp[kv+j]

显而易见,m 一定等于 kv + j,其中 0 <= j < v
所以,我们可以把 dp 数组分成 j 个类,每一类中的值,都是在同类之间转换得到的
也就是说,dp[k
v+j] 只依赖于

{ dp[j], dp[v+j], dp[2v+j], dp[3v+j], … , dp[k*v+j] }

因为我们需要的是{ dp[j], dp[v+j], dp[2v+j], dp[3v+j], … , dp[k*v+j] } 中的最大值,
可以通过维护一个单调队列来得到结果。这样的话,问题就变成了 j 个单调队列的问题
所以,我们可以得到

dp[j] = dp[j] dp[j+v] = max(dp[j] + w, dp[j+v]) dp[j+2v] =
max(dp[j] + 2w, dp[j+v] + w, dp[j+2v]) dp[j+3v] = max(dp[j] + 3w,
dp[j+v] + 2w, dp[j+2v] + w, dp[j+3v])

但是,这个队列中前面的数,每次都会增加一个 w ,所以我们需要做一些转

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值