多重背包问题——单调队列优化

这篇具有很好参考价值的文章主要介绍了多重背包问题——单调队列优化。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、多重背包问题

我们在之前的文章中曾经讲解过多重背包问题,当时我们讲解了两种方法,一种方法就是三重循环,这种方法最为朴素好想。但是这种方法的时间复杂度非常高,后来我们想到了二进制优化的方式。那么今天我们将再介绍一种更好的优化方式——单调队列优化。

在讲解这种优化方式之前,建议大家先去看看作者之前对另外两种方法的讲解,传送门:多重背包问题(详解二进制优化原理)

二、单调队列优化

1、思路

我们观察一下多重背包问题中的转移方程,如下图所示:
单调队列优化多重背包,# DP与贪心题目,算法
我们发现j,j-v等等都是同余于v的。也就是说,我们的转移方程只会用到余数相等的状态。基于这个观点,我们将容量从0–m按照余数分类。
就像图中的黑色笔记。

那么对于任意一个状态,在容量允许的条件下,我们会向前数s个,(s是物品的个数,这里最多数s个,如果容量装不下了就会小于s个)。然后我们在这s个余数相同的状态中选出一个最大值。如图中的红色框所示。我们可以将这个框看作一个滑动窗口,因为随着图中系数y的增加,这个窗口也在向右移动,即滑动。

那么我们如何构造这个滑动窗口呢?

我们刚刚将0到m之间的数字按照余数分为了若干组,那么现在我们拿出一组写成转移方程,观察一下如何构造滑动窗口。如下图所示:
单调队列优化多重背包,# DP与贪心题目,算法
我们的单调队列存储的是下标,也就是说下标对应着一个固定的状态值。但我们看图中的状态,下标为x的状态所对应的值都不一样。也就是说下标所对的状态都变,既然在变,我们的窗口中的值就很难比较大小。

因此,我们需要经过一个变化,让窗口内下标所对的状态值不变。那么怎么变呢?很简单,我们将后面加的几w提出来。

单调队列优化多重背包,# DP与贪心题目,算法
此时我们就发现,我们max中比较的对象都一致了,这样的话,我们就可以将这些数构造成一个单调减的滑动窗口。

我们还可以观察到,窗口内的状态在不断地-w,但是系数都不同,那么这个系数有什么规律呢?
单调队列优化多重背包,# DP与贪心题目,算法知道这个规律的目的在于滑动窗口内元素的比较。比如我们碰到一个新的状态值,我们需要计算出其相对于余数的偏移量然后对这个状态进行减几个w的操作,之后这个值才能放到窗口内。

此时我们将x+sv换成j,因为我们循环中肯定是用j来枚举的,所以换成j来表达易于后面写代码。
单调队列优化多重背包,# DP与贪心题目,算法
但是我们还还有不选这个物品的情况,需要将其加入到队列中,即下图所示,
单调队列优化多重背包,# DP与贪心题目,算法
我们需要利用这个式子判断f[i-1][j]是否有可能是最大值,即将这个数加入队列中。然后我们就可以根据最值更新f[i][j]了,即:

 f[i][j]=f[i-1][q[hh]]+((j-q[hh])/v[i])*w[i];

接下来我们就可以写代码了,按照余数分组,按照偏移量构造队列,选出最值得到当前状态。文章来源地址https://www.toymoban.com/news/detail-611870.html

2、代码

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=1e3+10,M=2e4+10;
int f[N][M],v[N],w[N],s[N],q[M];
int n,m;
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)scanf("%d%d%d",v+i,w+i,s+i);
    for(int i=1;i<=n;i++)
    {
        for(int x=0;x<v[i];x++)
        {
            int hh=0,tt=-1;
            for(int j=x;j<=m;j+=v[i])
            {
                if(hh<=tt&&q[hh]<j-s[i]*v[i])hh++;
                while(hh<=tt&&f[i-1][q[tt]]-(q[tt]-x)/v[i]*w[i]<f[i-1][j]-(j-x)/v[i]*w[i])tt--;
                q[++tt]=j;
                f[i][j]=f[i-1][q[hh]]+((j-q[hh])/v[i])*w[i];
            }
        }
    }
    cout<<f[n][m]<<endl;
    return 0;
}

到了这里,关于多重背包问题——单调队列优化的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 前缀和+单调双队列+贪心:LeetCode2945:找到最大非递减数组的长度

    C++算法:前缀和、前缀乘积、前缀异或的原理、源码及测试用例 包括课程视频 单调双队列 贪心 给你一个下标从 0 开始的整数数组 nums 。 你可以执行任意次操作。每次操作中,你需要选择一个 子数组 ,并将这个子数组用它所包含元素的 和 替换。比方说,给定数组是 [1,3,

    2024年02月03日
    浏览(11)
  • 背包问题分析代码详解【01背包+完全背包+多重背包】

    一、01背包问题 问题描述: 有 N 件物品和一个容量为 V 的背包,每件物品有各自的价值且只能被选择一次,要求在有限的背包容量下,装入的物品总价值最大。 朴素01背包 状态f[i , j]定义:在前i个物品中选,总体积不超过j的价值最大值 状态转移 1) 选第i个物品:f[i,j] = f

    2024年02月06日
    浏览(14)
  • 动态规划——决策单调性优化DP 学习笔记

    对于最优性问题,常有状态转移方程: (f_i = min/max{f_jdots}) , 形象的:如果 (i) 的最优转移点是 (j) , (i\\\') 的最优转移点是 (j\\\') ,当 (ii\\\') 时,有 (jle j\\\') ,则称该 DP 问题具有决策单调性。 即: (i) 单增,其最优转移点单调不减。 如何发现一个转移方程具有决策

    2024年02月08日
    浏览(19)
  • 【LeetCode题目详解】第八章 贪心算法 part06 738.单调递增的数字 968.监控二叉树 (day37补)

    当且仅当每个相邻位数上的数字  x  和  y  满足  x = y  时,我们称这个整数是 单调递增 的。 给定一个整数 n ,返回 小于或等于 n 的最大数字,且数字呈 单调递增 。 示例 1: 示例 2: 示例 3: 提示: 0 = n = 109 # 暴力解法 题意很简单,那么首先想的就是暴力解法了,来我替大家

    2024年02月10日
    浏览(12)
  • 力扣第738题 单调递增的数字 c++ 暴力超时 贪心优化

    738. 单调递增的数字 中等 相关标签 贪心  数学 当且仅当每个相邻位数上的数字  x  和  y  满足  x = y  时,我们称这个整数是 单调递增 的。 给定一个整数  n  ,返回  小于或等于  n  的最大数字,且数字呈  单调递增  。 示例 1: 示例 2: 示例 3: 提示: 0 = n = 109 从N开始

    2024年02月08日
    浏览(13)
  • 【算法日志】动态规划刷题:01背包问题,多重背包问题(day37,day38)

    目录 前言 目标和(01背包) 一和零(01背包) 零钱兑换(多重背包) 排列总和(多重背包) 这两天都是背包问题,其中的01背包的一些应用问题需要一定的数学建模能力,需要i将实际问题简化成我们熟悉的背包问题;而这两天的多重背包问题还算比较基础,但也要我明白了

    2024年02月11日
    浏览(14)
  • 【十七】【动态规划】DP41 【模板】01背包、416. 分割等和子集、494. 目标和,三道题目深度解析

    动态规划就像是解决问题的一种策略,它可以帮助我们更高效地找到问题的解决方案。这个策略的核心思想就是将问题分解为一系列的小问题,并将每个小问题的解保存起来。这样,当我们需要解决原始问题的时候,我们就可以直接利用已经计算好的小问题的解,而不需要重

    2024年02月03日
    浏览(19)
  • 从01背包开始动态规划:暴力解法 + dp + 滚动数组 + dp优化

        01背包问题是动态规划中最经典的问题之一,本篇将通过给出其四种解法,使读者更深刻理解动态规划。   有N件物品和一个容量是 V 的背包,每个物品有各自的体积和价值,且每个物品只能放一次(这也是01背包名字的由来),如何让背包里装入的物品具有最大的价值总

    2024年04月17日
    浏览(20)
  • 算法篇——动态规划 完全和多重背包问题 (js版)

    01 背包 问题和 完全背包 问题的不同点在于,所有的物品只能 使用一次 ,判断  哪些物品  装进背包里 物品价值和 最大;而 完全背包 问题中,所有物品都能 使用n次 ,判断 哪个物品 装 n 个进去 物品价值和 最大。 01 背包的递推公式是: 【当然先遍历物品还是背包的容量

    2024年02月08日
    浏览(17)
  • 蓝桥杯算法全集之多重背包问题I(动态规划算法)

    有 N 种物品和一个容量是 V 的背包。 第 i 种物品最多有 s i 件,每件体积是 v i ,价值是 w i 。 求解将哪些物品装入背包,可使物品体积总和不超过背包容量,且价值总和最大。 输出最大价值。 用下面这个图来分别动态规划的四个经典背包问题 定义状态的含义(这一步需要

    2023年04月08日
    浏览(11)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包