【算法】----多重背包问题I,II(动态规划)

🌹作者:云小逸
📝个人主页:云小逸的主页
📝Github:云小逸的Github
🤟motto:要敢于一个人默默的面对自己,强大自己才是核心。不要等到什么都没有了,才下定决心去做。种一颗树,最好的时间是十年前,其次就是现在!学会自己和解,与过去和解,努力爱自己。==希望春天来之前,我们一起面朝大海,春暖花开!==🤟
👏专栏:C++👏 👏专栏:Java语言👏👏专栏:Linux学习👏
👏专栏:C语言初阶👏👏专栏:数据结构👏👏专栏:备战蓝桥杯👏


前言

今天我们接着上一篇博客继续学习背包问题:多重背包问题,这里将介绍完全背包问题的二维解法和一维解法以及优化版本,希望你可以喜欢。在这里插入图片描述——————————————————————————————

多重背包问题

多重背包问题是背包问题的一个变种。在这个问题中,每个物品有一个重量和一个价值,且可重复选择多次。背包有一个容量限制,问怎样选择物品可以使得背包中的总价值最大。

二维多重背包

对于二维多重背包问题,我们可以将其转化为一维多重背包问题来解决。具体来说,我们可以将第 i i i 个物品拆成 s i s_i si 个物品,每个物品的重量和价值都是原来的 w i s i \frac{w_i}{s_i} siwi v i s i \frac{v_i}{s_i} sivi。这样就将二维多重背包问题转化为了一维多重背包问题。

代码实现如下:

int dp[N];
for (int i = 1; i <= n; i++) {
    for (int j = m; j >= w[i]; j--) {
        for (int k = 1; k <= s[i] && k * w[i] <= j; k++) {
            dp[j] = max(dp[j], dp[j - k * w[i]] + k * v[i]);
        }
    }
}

时间复杂度为 O ( n m ∑ i = 1 s v i ) O(nm\sum\limits_{i=1}^s v_i) O(nmi=1svi)

一维多重背包

对于一维多重背包问题,我们可以使用动态规划来解决。设 d p [ i ] [ j ] dp[i][j] dp[i][j] 表示前 i i i 个物品中,容量为 j j j 的背包所能装下的最大价值。则有以下状态转移方程:

d p [ i ] [ j ] = max ⁡ { d p [ i − 1 ] [ j − k ⋅ w i ] + k ⋅ v i } ( 0 ≤ k ≤ ⌊ j w i ⌋ ) dp[i][j] = \max\{dp[i-1][j-k\cdot w_i]+k\cdot v_i\} \quad (0\leq k\leq \lfloor\frac{j}{w_i}\rfloor) dp[i][j]=max{dp[i1][jkwi]+kvi}(0kwij⌋)

其中 w i w_i wi 表示第 i i i 个物品的重量, v i v_i vi 表示第 i i i 个物品的价值。这个方程的意思是,我们可以选择第 i i i 个物品的 k k k 个,然后再加上前 i − 1 i-1 i1 个物品在剩余容量 j − k ⋅ w i j-k\cdot w_i jkwi 的情况下所能取得的最大价值。

代码实现如下:

int dp[N];
for (int i = 1; i <= n; i++) {
    for (int j = m; j >= w[i]; j--) {
        for (int k = 1; k * w[i] <= j && k <= s[i]; k++) {
            dp[j] = max(dp[j], dp[j - k * w[i]] + k * v[i]);
        }
    }
}

时间复杂度为 O ( n m ∑ i = 1 s v i ) O(nm\sum\limits_{i=1}^s v_i) O(nmi=1svi)

优化版本

以上两种方法的时间复杂度都比较高,无法通过本题。我们需要对其进行优化。

观察上面的状态转移方程,我们可以发现其中有一个 max ⁡ \max max 函数,这个函数是比较耗时的。我们可以使用单调队列来优化这个 max ⁡ \max max 函数。具体来说,我们可以将 d p [ i − 1 ] [ j − k ⋅ w i ] + k ⋅ v i dp[i-1][j-k\cdot w_i]+k\cdot v_i dp[i1][jkwi]+kvi 放入一个单调队列中,然后取队首元素即可。

代码实现如下:

int dp[N];
deque<int> q;
for (int i = 1; i <= n; i++) {
    for (int j = 0; j < w[i]; j++) {
        q.clear();
        for (int k = 0; k * w[i] + j <= m; k++) {
            int x = k * w[i] + j;
            if (!q.empty() && k - q.front() > s[i]) {
                q.pop_front();
            }
            if (!q.empty()) {
                dp[x] = max(dp[x], dp[x - w[i]] + k * v[i]);
                while (!q.empty() && dp[x - w[i]] - q.back() * v[i] >= 0) {
                    q.pop_back();
                }
            }
            q.push_back(k);
        }
    }
}

时间复杂度为 O ( n m log ⁡ s ) O(nm\log s) O(nmlogs)


最后

十分感谢你可以耐着性子把它读完和我可以坚持写到这里,送几句话,对你,也对我:

1. 努力读书,尤其是家境普通或者家境差的,去学习,你的目标就是改变自己的命运,骆家辉三代人才进白宫,英国印度裔首相苏纳克,三代人才进白金汉宫,所以有一代人必须做出付出,没办法,你的最大任务就是完成原始资本积累。

2.不要被别人牵着鼻子走,不要别人说什么就信什么,学会分辨是非。

3.不要随便把情绪写在脸上,冷静不代表软弱,理智不等于认怂。

4.我们不能一边过着糟糕的生活,一边期待好事发生在我们身上。

5.穷不沾色,富不沾赌。

最后如果觉得我写的还不错,请不要忘记点赞✌,收藏✌,加关注✌哦(。・ω・。)

愿我们一起加油,奔向更美好的未来,愿我们从懵懵懂懂的一枚菜鸟逐渐成为大佬。加油,为自己点赞!

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 7
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

云小逸

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值