多重背包问题的三种解法(转化为01背包、二进制拆分、单调队列优化)

news2024/11/20 2:32:20

多重背包问题的三种解法

  • 转化为01背包
  • 二进制拆分优化
  • 单调队列优化

转化为01背包

题目链接:acwing4. 多重背包问题 I
题目描述
在这里插入图片描述
数据范围
在这里插入图片描述
思路:
可以转化为01背包问题求解,将s个物品都看作单独的一个物品,时间复杂度为 O ( N ∗ V ∗ S ) O(N*V*S) O(NVS)
代码如下:

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<vector>
using namespace std;
typedef pair<int ,int> pii;
const int N=110;

int f[N];

int main(){
    int n,m;
    vector<pii> vv;
    cin>>n>>m;
    for(int i=0;i<n;i++){
        int v,w,s;
        scanf("%d%d%d",&v,&w,&s);
        for(int j=0;j<s;j++) vv.push_back({v,w});
            
    }
    for(int i=0;i<vv.size();i++)
        for(int j=m;j>=vv[i].first;j--)
            f[j]=max(f[j],f[j-vv[i].first]+vv[i].second);
    cout<<f[m];
    return 0;
}

二进制拆分优化

题目链接:acwing5. 多重背包问题 II
数据范围变大:
在这里插入图片描述
这时直接拆分为s份,转化为01背包问题求解会超时,考虑二进制拆分,二进制拆分参考博客
主要思路还是将其转化为01背包问题来求解,但是我们不必要将s个物品给看成s个单独的物品,举个例子,二进制拆分是这样的:

10=1+2+4+3=2^0 + 2^1 + 2^2 + (10-2^0 + 2^1 + 2^2)
1~10中的每一个数都可以由1、2、4、3这四个数来表示出来,这样我们就不需要将s个物品拆分为s个单独的物品了。

时间复杂度为 O ( N ∗ V ∗ l o g ( s ) ) O(N*V*log(s)) O(NVlog(s))
代码如下:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
typedef long long ll;
typedef pair<ll,ll> pii;
const int N=2e3+10;

ll f[N];

int main(){
    int n,m;
    vector<pii> vv;
    cin>>n>>m;
    for(int i=0;i<n;i++){
        int v,w,s;
        scanf("%d%d%d",&v,&w,&s);
        for(int t=1;t<=s;t*=2){
            vv.push_back({(ll)t*v,(ll)t*w});
            s-=t;
        }
        if(s) vv.push_back({(ll)s*v,(ll)s*w});
    }
    
    for(int i=0;i<vv.size();i++)
        for(int j=m;j>=vv[i].first;j--) f[j]=max(f[j],f[j-vv[i].first]+vv[i].second);
    cout<<f[m];
    return 0;
}

单调队列优化

数据范围继续变大
在这里插入图片描述
这里考虑用单调队列优化,首先分析01背包与完全背包,进而推导出多重背包的单调队列优化。

01背包:
用f[i][j]来表示考虑前i个物品,当前背包容量为j时的能装的最大价值
选或者不选物品i
f[i][j]=max(f[i-1][j],f[i-1][j-v]+w)
由于f[i]这一层只与上一层f[i-1]有关,所以我们考虑优化空间为一维
f[j]=max(f[j],f[j-v]+w)//等号左边的f[j]表示的是f[i][j],等式右边的f[j]表示的是f[i-1][j]
需要注意的地方是,如果我们从小到大遍历j的话,那么等式右边的f[j-v]表示的是f[i][j-v]
所以,我们需要从大到小枚举体积j

也就是:
for(int j=m;j>=v;j--) //v ,m为第i个物品的体积和价值
	f[j]=max(f[j],f[j-v]+w)
完全背包问题:
考虑选多少个物品i最好:(s为最多装多少个物品i,这点与多重背包不同,需要注意)
f[i][j]  =max(f[i-1][j],f[i-1][j-v]+w,f[i-1][j-2*v]+2*w,....,,f[i-1][j-s*v]+s*w)
可以发现:
f[i][j-v]=max(f[i-1][j-v]+w,f[i-1][j-2*v]+2*w,....,,f[i-1][j-s*v]+s*w)
观察上面可以得出:
f[i][j]=max(f[i-1][j],f[i][j-v]);
考虑对空间优化:
f[j]=max(f[j],f[j-v]);
这里遍历体积是从小到大遍历的,因为我们要的就是让等式左边的f[j-v]表示的是f[i][j-v]而不是f[i-1][j-v]

也就是:
for(int j=v;j<=m;j++) 
	f[j]=max(f[j],f[j-v]+w)
多重背包问题:
看懂了上面两步,我们可以来进行多重背包问题的推导
考虑物品i的个数为s,也就是最多被选s次

考虑选多少个物品i最好(<=s):
f[i][j]    =max(f[i-1][j],f[i-1][j-v]+w,f[i-1][j-2*v]+2*w,....,f[i-1][j-s*v]+s*w)
f[i][j-v]  =max(         f[i-1][j-v],f[i-1][j-2*v]+w,....,f[i-1][j-s*v]+(s-1)*w,f[i-1][j-(s+1)v]+sw)//注意这个地方的区别,最多选s个
f[i][j-2*v]=max(         f[i-1][j-2*v],f[i-1][j-3*v]+w,....,f[i-1][j-s*v]+(s-2)*w,f[i-1][j-(s+1)v]+(s-1)w,f[i-1][j-(s+2)*v]+s*w)//注意这个地方的区别,最多选s个
我们可以观察到,f[i][j-v]比f[i][j-2*v]多了一项f[i-1][j-v],少了一项f[i-1][j-(s+2)*v],
f[i][j]与f[i][j-v]的关系也是类似,这里我们可以想到学过的数据结构——单调队列,这样可以快速求出max,不过需要注意的是,按照加入队列的顺序不同,要加入不同的w,需要维持一个等差的关系开判断是否入队出队。

在这里插入图片描述

时间复杂度为 O ( N ∗ M ) O(N*M) O(NM)
代码如下:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=20010;

int f[N];
int g[N],q[N];
int main(){
    int n,m;
    cin>>n>>m;
    for(int i=0;i<n;i++){
        int v,w,s;
        scanf("%d%d%d",&v,&w,&s);
        memcpy(g,f,sizeof f);
        for(int j=0;j<v;j++){
            int hh=0,tt=-1;
            for(int k=j;k<=m;k+=v){
                if(tt>=hh&&k-s*v>q[hh]) hh++;//队尾出队
                if(tt>=hh) f[k]=max(g[k],g[q[hh]]+(k-q[hh])/v*w);//求出在队尾的最大值
                while(hh<=tt&&g[k]>=g[q[tt]]+(k-q[tt])/v*w) tt--;//维护单调队列
                q[++tt]=k;//入队
            }
        }
    }
    cout<<f[m]<<endl;
    return 0;
}


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/444539.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【一】MATLAB基础知识

【一】MATLAB基础知识 1 数值数据类型的分类 整型 无符号整数&#xff1a;无符号8位整数、无符号16位整数、无符号32位整数、 无符号64位整数。 带符号整数&#xff1a;带符号8位整数、带符号16位整数、带符号32位整数、 带符号64位整数。 无符号8位整数数据范围&#xff…

树和二叉树(概念及其结构)

1.树概念及结构&#xff08;了解&#xff09;‘ 1.1树的概念 树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个有限结点组成一个具有层次关系的集合。把它 叫做树是因为它看起来像一颗倒挂的树&#xff0c;也就是说它是根朝上&#xff0c;而叶…

php+vue+mysql校园大学生兼职信息网站系统

商家功能模块 商家通过点击后台管理&#xff0c;进入页面可以进行首页、个人中心、热门兼职管理、兼职接单管理、学生咨询管理、兼职任务管理、完成评价管理等功能模块&#xff0c;进行相对应操作 兼职接单管理&#xff1a;通过兼职接单管理可以进行获取兼职名称、专业、分类、…

佳电股份:智能互联 绿色驱动 拥抱未来

4月 13—15 日&#xff0c;2023年易派客工业品展览会、石油石化工业展览会、第七届中国石油和化工行业采购年会&#xff0c;在苏州国际博览中心举行。在本次展会上&#xff0c;佳电股份展出了超高速永磁电机、超高效高压三相异步电动机、智慧电机以及配套服务等主要产品。 哈尔…

linux 下 mysql 平滑升级,不暴力

只适合版本跨越较小的&#xff0c;如果从5到8这种不支持 查看当前版本5.6.40,升级到5.6.50&#xff08;因为一些漏洞的原因&#xff09; 1&#xff1a;下载需要升级的版本 2&#xff1a;解压 3&#xff1a;停止当前的mysql服务 service mysql stop 4&#xff1a;备份原先系…

Spring Boot的基础使用和< artifactId>spring-boot-maven-plugin</ artifactId>爆红的处理

Spring Boot的基础使用和< artifactId>spring-boot-maven-plugin</ artifactId>爆红的处理 Spring Boot概述 微服务概述 微服务Microservices是一种软件架构风格&#xff0c;他是以专注于单一责任与功能的小型功能区块Small Building Blocks 为基础&#xff0c;…

FL Studio21安装体验试用下载fl水果支持最新中文语言功能

FL Studio是什么&#xff1f;如果你打算将来朝着艺术和音乐方向发展&#xff0c;那么学习音乐理论和音乐制作就是一门基础了。FL Studio 21还提供了几十个内置的音乐和声音样本库&#xff0c;以及多种音频效果处理器和虚拟乐器&#xff0c;包括合成器、鼓机、效果器等。这些插件…

【C++初阶】:类与对象(上)

类与对象 一.面向对象的初步认识二.初步认识类三.类的权限四.类的声明和定义五.封装六.类的实例化七.类的大小 一.面向对象的初步认识 C语言是面向过程的&#xff0c;关注的是过程&#xff0c;分析出求解问题的步骤&#xff0c;通过函数调用逐步解决问题。 例如洗衣服 而C是基于…

GFD233A 3BHE022294R0103

GFD233A 3BHE022294R0103 ABB KUC321AE PLC模块 HIEE300698R0001 KU C321 AE01 ABB KUC711 3BHB004661R0001 高压变频模块 KUC711AE ABB KUC755AE105 3BHB005243R0105 驱动控制系统模块 KUC755 ABB KUC755AE106 3BH005243R006 控制系统模块 KU C755 AE 106 ABB LDGRB-01 3BSE01…

react-10 函数式写法rsf,配合HOOKS钩子函数

函数式跨组件通信&#xff1a; useContext 实现跨组件传值&#xff0c;内层组件获取context中的值 用来解决同一个父组件的后代组件之间的数据共享问题, 同一个父组件的所有后代组件都可以用 useContext() 从最近的 context 中获取. 性能优化&#xff1a;useMemo &#xff1a…

cv2 五边形矫正,python ,多边形透视变换

#图像透视变换--矫正 #根据最大的5边形进行透视变换 #获取最大和最次长 周长对应的轮廓 #该轮廓进行5边形拟合逼近 #进行透视变换&#xff1a;应用两线交点 import numpy as np import cv2#大津阈值法 OSTU def myApprox(con,pointnum5):# con为预先得到的最大轮廓num 0.001…

2023年CDGA/CDGP数据治理工程师认证报名需要什么条件?

DAMA认证为数据管理专业人士提供职业目标晋升规划&#xff0c;彰显了职业发展里程碑及发展阶梯定义&#xff0c;帮助数据管理从业人士获得企业数字化转型战略下的必备职业能力&#xff0c;促进开展工作实践应用及实际问题解决&#xff0c;形成企业所需的新数字经济下的核心职业…

mybatis01-Lombok、mybatis原理、参数处理、模糊查询、结果封装

mybatis01 Lombok 一、Lombok的使用 Lombok 是一个Java库&#xff0c;能自动插入编辑器并构建工具&#xff0c;简化Java开发。通过加注解的方式&#xff0c;不需要为类编写getter、setter、constructor或equals&#xff0c;同时可以自动化日志变量。 第一步、在pom.xml中加…

基于动态车辆模型的百度Apollo LQR和MPC横向控制算法分析(Matlab代码实现)

目录 &#x1f4a5;1 概述 &#x1f4da;2 运行结果 &#x1f389;3 参考文献 &#x1f468;‍&#x1f4bb;4 Matlab代码 &#x1f4a5;1 概述 Apollo 是由百度发起的一个高效、灵活的基于自动驾驶的测试和研发的平台。Apollo 的主要逻辑为局部规划 轨道跟踪。在局部规划…

4.1 插值概念与基础理论

学习目标&#xff1a; 学习插值的基础理论可以从以下几个方面入手&#xff1a; 理解插值的概念&#xff1a;插值是指根据已知数据点的函数值&#xff0c;构造出经过这些点的函数&#xff0c;用于在已知数据点之间估计函数值。可以将其看做是一种函数逼近的方法。 掌握插值多项…

【Linux】MySQL高可用之Mysql读写分离实践

一、MySQL读写分离原理 读写分离就是在主服务器上修改&#xff0c;数据会同步到从服务器&#xff0c;从服务器只能提供读取数据&#xff0c;不能写入&#xff0c;实现备份的同时也实现了数据库性能的优化&#xff0c;以及提升了服务器安全。 二、读写分离实践 绝大多数的企业的…

居家办公远程控制电脑怎么操作

居家办公或者混合办公&#xff0c;正成为一种新的流行趋势。如何更好地居家办公&#xff0c;实现更高的工作效率和更舒适办公体验&#xff0c;我们总结出如下建议。 无论您是每周远程工作几天还是全职工作&#xff0c;无论是出于选择还是因为健康状况或天气事件&#xff0c;都…

部署YUM仓库及NFS共享服务

一、YUM仓库服务 1&#xff09;YUM概述 YUM&#xff08;Yellow dog Updater Modified&#xff09; 基于RPM包构建的软件更新机制 可以自动解决依赖关系 所有软件包由集中的YUM软件仓库提供 linux本身就是以系统简洁为自身优势&#xff0c;所以在安装操作系统的时候并没有将…

Kaggle往期赛 | 多目标推荐系统大赛baseline

来源&#xff1a;深度之眼 作者&#xff1a;比赛教研部 编辑&#xff1a;学姐 Kaggle OTTO – Multi-Objective Recommender System多目标推荐系统大赛 赛题分析baseline 1、赛题链接 https://www.kaggle.com/competitions/otto-recommender-system/overview 2、赛题描述 本…

聚观早报 |字节与Meta争夺VR开发者;苹果设备无故要求输入ID密码

今日要闻&#xff1a;字节与Meta争夺VR应用开发者&#xff1b;苹果设备无故要求输入ID密码&#xff1b;余承东称25年是智能电动汽车分水岭&#xff1b;小鹏回应G6售价及配置信息曝光&#xff1b;亚马逊将在爱尔兰裁员200人 字节与Meta争夺VR应用开发者 4 月 14 日消息&#xf…