算法:多重背包问题dp

news2024/11/27 1:42:01

文章目录

    • 一、多重背包问题特点
      • 1.1、多重背包问题的特征
      • 1.2、解决多重背包问题的基本方法
        • 典型例题:AcWing——多重背包问题I
      • 1.3、二进制优化
        • 1.3.1、二进制优化的思想
        • 1.3.2、多重背包问题的二进制优化

在这里插入图片描述

一、多重背包问题特点

多重背包问题是背包问题的又一变种,它在0-1背包和完全背包问题的基础上增加了一个限制:每种物品i除了有一个重量w[i]和价值v[i]外,还有一个最大可用数量n[i]。这意味着每种物品i可以被选取的次数最多是n[i]次,而不是只有一次(0-1背包问题)或无限次(完全背包问题)。

1.1、多重背包问题的特征

  1. 有限的物品数量:每种物品有一个最大数量限制,不能无限制地选择。
  2. 背包容量限制:存在一个容量限制,所有选取的物品的总重量不能超过这个限制。
  3. 优化目标:目标是在不超过背包容量的前提下,最大化背包内物品的总价值。
  4. 复杂度:时间和空间复杂度取决于具体的实现方法,一般时间复杂度为O(V*sum(n[i]))

1.2、解决多重背包问题的基本方法

解决多重背包问题的基本思路是利用动态规划,其中最直观的方法是使用二维DP数组dp[i][j],表示考虑前i种物品,在不超过重量j的情况下的最大价值。和0-1背包问题的区别在于物品i能取n[i]次,因此状态转移方程可以写为:

for(int k=0;k<=n[i];++k)
	if(j-k*weight[i]>=0)
		dp[i][j]=max(dp[i][j],dp[i-1][j-k*weight[i]]+k*value[i]);

这里,k是从0n[i]的整数,表示选择第i种物品k次的可能性。

由于这种方法会导致较高的时间复杂度,时间复杂度为O(V*sum(n[i])),特别是当n[i]的值很大时,常常需要使用其他技巧。

典型例题:AcWing——多重背包问题I

AcWing:多重背包问题I
按照以上思路,并且按照0-1背包一样的思路,进行降维优化。

    for(int i=0;i<N;++i)
        for(int j=V;j>=volume[i];--j)
            for(int k=0;k<=n[i];++k)
                if(j-k*volume[i]>=0)
                    dp[j]=max(dp[j],dp[j-k*volume[i]]+k*value[i]);

本题可以书写代码为:

#include<bits/stdc++.h>
using namespace  std;
int dp[101];
int main(void){
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    int N,V;
    cin>>N>>V;

    vector<int> volume(N);
    vector<int> value(N);
    vector<int> n(N);

    for(int i=0;i<N;++i){
        cin>>volume[i]>>value[i]>>n[i];
    }
    for(int i=0;i<N;++i)
        for(int j=V;j>=volume[i];--j)
            for(int k=0;k<=n[i];++k)
                if(j-k*volume[i]>=0)
                    dp[j]=max(dp[j],dp[j-k*volume[i]]+k*value[i]);
    cout<<dp[V];
    return 0;
}

1.3、二进制优化

1.3.1、二进制优化的思想

对于任何一个数,我们可以将其进行二进制拆分。即任何一个10进制数都能写成二进制数的形式。
比如:3=1+2=11B、10=2+8=1010B。

如果我们对于一个数,例如10,取出小于其的所有二进制位,即1B,10B,100B,1000B,那么我们必然能够选出其中的某些位来凑成10,并且对于小于10的任何一个正整数也可以被凑成,即选取其中若干位有:1B、10B、11B、100B、101B、110B、111B、1000B、1001B···。即,如果我们有一个物品,它能够被选择小于等于n次,我们可以通过选择其中的某些位来实现选择的所有情况。

那么我们把一个物品可以最多选择n次的问题,按照未优化的多重背包问题需要进行O(V*sum(n[i]))次计算取最大值 变成了
考虑在logn个物品中选择其中的某些物品,取最大值 的问题了。按到理来说,logn个物品要么被选要么不被选,一共是2的logn次方种情况,也就是n种情况;但是如果我们把这个问题转化成0-1背包问题,即利用动态规划来考虑,就变成了O(V*sum(logn[i]))次了。当n[i]<=2000时,logn[i]<=3.301,减少了一千倍计算量。

因此,我们对于n[i],可以进行二进制拆分,将n[i]个物品按照二进制拆分,变成若干堆,每次选择只能一次全选,这样使得我们需要考虑的物品变成logn[i]个,多重背包问题变成了一个0-1背包问题,即这logn[i]个物品,要么被选,要么不被选,能够取得的最大值。我们通过上述叙述可以知道logn[i]个物品的所有被选择的情况,刚好构成了0~n[i]中的所有数字。

由于一个物品的数量n不一定是2的整数倍,因此我们在考虑二进制的时候,因为我们的目的是凑成0~ n,因此我们在考虑二进制的时候,我们考虑到小于等于n/2位即可,它们能满足0~ k种情况(k<=n/2),然后剩余的n-k部分直接单独成一块就行,这样,能满足n-k~ k+n-k种情况,合并起来就是0~n中情况。

1.3.2、多重背包问题的二进制优化

通过二进制拆分,我们将m个物品每个最多选n[i]次的多重背包问题,转换成了 sum(logn[i])个物品的0-1背包问题。相当于进行了问题转换。

代码:

#include<bits/stdc++.h>
using namespace  std;
int dp[2002];
int main(void){
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    int N,V;
    cin>>N>>V;

    vector<int> value;
    vector<int> volume;
    for(int i=0;i<N;++i){//构建二进制拆分物品
        int w,v,num;
        cin>>w>>v>>num;//w单物品体积,v单物品价值,num可选数量
        int s=num;
        int b=1;
        while(b<=s){//注意b必须是小于num,且不能是最高位 如1010B,b不能是1000B
            value.push_back(b*v);
            volume.push_back(b*w);
            s-=b;
            b*=2;
        }
        if(s>0){
            value.push_back(s*v);
            volume.push_back(s*w);
        }
    }
    
    N=value.size();//更新物品数量
    
    for(int i=0;i<N;++i)
        for(int j=V;j>=volume[i];--j)
            dp[j]=max(dp[j],dp[j-volume[i]]+value[i]);

    cout<<dp[V];
    return 0;
}

位数关系即:

        int s=num;
        int b=1;
        num=log2(num);
        num=pow(2,num-1);
        while(b<=num){
            value.push_back(b*v);
            volume.push_back(b*w);
            s-=b;
            b*=2;
        }
        if(s>0){
            value.push_back(s*v);
            volume.push_back(s*w);
        }
        int s=num;
        int b=1;
        num=num>>1;
        while(b<=num){
            value.push_back(b*v);
            volume.push_back(b*w);
            s-=b;
            b*=2;
        }
        if(s>0){
            value.push_back(s*v);
            volume.push_back(s*w);
        }

官方:

#include<iostream>
using namespace std;

const int N = 12010, M = 2010;

int n, m;
int v[N], w[N]; //逐一枚举最大是N*logS
int f[M]; // 体积<M

int main()
{
    cin >> n >> m;
    int cnt = 0; //分组的组别
    for(int i = 1;i <= n;i ++)
    {
        int a,b,s;
        cin >> a >> b >> s;
        int k = 1; // 组别里面的个数
        while(k<=s)
        {
            cnt ++ ; //组别先增加
            v[cnt] = a * k ; //整体体积
            w[cnt] = b * k; // 整体价值
            s -= k; // s要减小
            k *= 2; // 组别里的个数增加
        }
        //剩余的一组
        if(s>0)
        {
            cnt ++ ;
            v[cnt] = a*s; 
            w[cnt] = b*s;
        }
    }

    n = cnt ; //枚举次数正式由个数变成组别数

    //01背包一维优化
    for(int i = 1;i <= n ;i ++)
        for(int j = m ;j >= v[i];j --)
            f[j] = max(f[j],f[j-v[i]] + w[i]);

    cout << f[m] << endl;
    return 0;
}

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

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

相关文章

大厂设计师倾心推荐的在线作图免费网站

在当今数字时代&#xff0c;绘画已经成为各行各业的必备技能。无论你是设计师、学生、创作者还是业余爱好者&#xff0c;免费的在线绘图软件都是发挥创造力和表达想法的理想选择。本文将介绍七款强大免费的在线绘图软件&#xff0c;让你轻松实现自己的创作梦想。你可以在不安装…

功能测试_验证qq账号的合法性

案例&#xff1a;验证qq账号的合法性&#xff08;要求&#xff1a;6-10位的自然数&#xff09; 使用等价类设计用例案例&#xff1a; 步骤&#xff1a; 1:明确需求&#xff1a;qq账号的合法性 2:划分等价类&#xff1a;有效等价类、有效取值、无效等价类、无效取值 3&…

docker搭建EFK

目录 elasticsearch1.创建网络2.拉取镜像3.创建容器如果出现启动失败&#xff0c;提示目录挂载失败&#xff0c;可以考虑如下措施 开放防火墙端口4.验证安装成功重置es密码关闭https连接创建kibana用户创建新账户给账户授权 kibana1.创建容器2.验证安装成功3.es为kibana创建用户…

LeetCode-冗余连接(并查集)

每日一题&#xff0c;今天又刷到一道使用并查集来解决的问题&#xff0c;再次加深了一遍自己对并查集的印象和使用。 题目要求 树可以看成是一个连通且 无环 的 无向 图。 给定往一棵 n 个节点 (节点值 1&#xff5e;n) 的树中添加一条边后的图。添加的边的两个顶点包含在 1…

Windows11下Docker使用记录(一)

Docker使用记录&#xff08;一&#xff09; 简单介绍Docker安装Docker 常用命令Docker 可视化Docker 使用GPU可视化rviz、gazebo 在进行ROS项目开发时&#xff0c;如果只有一台Windows电脑&#xff0c;我们可以考虑使用WSL或Docker来搭建ROS环境。在尝试了两种方式后&#xff0…

【静态分析】静态分析笔记01 - Introduction

参考&#xff1a; BV1zE411s77Z [南京大学]-[软件分析]课程学习笔记(一)-introduction_南京大学软件分析笔记-CSDN博客 ------------------------------------------------------------------------------------------------------ 1. program language and static analysis…

Python实现滑块验证码识别,最简单的一种,没有任何加密

网址链接&#xff1a;衣丰 & 2010-聚衣网(juyi5.cn) - 常熟市聚衣网&#xff0c;聚衣网女装&#xff0c;江苏省女装批发&#xff0c;苏州市女装批发&#xff0c;常熟市女装批发&#xff0c;网销女装一件代发&#xff0c;全国最低价 平时采集数据&#xff0c;频率过快&…

ai伪原创文案,快速生成文案的方法!

在当今数字化时代&#xff0c;文案写作成为广告、营销等领域中不可或缺的一环。然而&#xff0c;随着互联网的发展&#xff0c;市场上的竞争愈发激烈&#xff0c;传统的文案写作方式已经无法满足大家的需求。ai伪原创文案的出现&#xff0c;便成为一种快速的写作文案的方法。本…

PowerJob 分布式任务调度简介

目录 适用场景 设计目标 PowerJob 功能全景 任务调度 工作流 分布式计算 动态容器 什么是动态容器? 使用场景 可维护性和灵活性的完美结合 实时日志&在线运维 PowerJob 系统组件 PowerJob 应用场景 PowerJob 的优势 PowerJob&#xff08;原OhMyScheduler&…

中国500米分辨率年最大EVI数据集

增强型植被指数&#xff08;EVI&#xff09;是在归一化植被指数&#xff08;NDVI&#xff09;改善出来的&#xff0c;根据大气校正所包含的影像因子大气分子、气溶胶、薄云、水汽和臭氧等因素进行全面的大气校正&#xff0c;EVI大气校正分三步&#xff0c;第一步是去云处理。第…

基于SpringBoot+Vue网上医院预约挂号系统+jsp(源码+部署说明+演示视频+源码介绍+lw)

您好&#xff0c;我是码农飞哥&#xff08;wei158556&#xff09;&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。&#x1f4aa;&#x1f3fb; 1. Python基础专栏&#xff0c;基础知识一网打尽&#xff0c;9.9元买不了吃亏&#xff0c;买不了上当。 Python从入门到精通…

python使用uiautomator2操作雷电模拟器9

之前写过一篇文章 python使用uiautomator2操作雷电模拟器_uiautomator2 雷电模拟器-CSDN博客 上面这篇文章用的是雷电模拟器4&#xff0c;雷电模拟器4.0.78&#xff0c;android版本7.1.2。 今天有空&#xff0c;再使用雷电模拟器9&#xff0c;android版本9来测试一下 uiauto…

绝地求生29.1版本更新后进不去 绝地求生更新后进不去游戏怎么办

绝地求生游戏共有两种主要模式&#xff1a;第一人称模式和第三人称模式。在这两种模式下玩家可以分别进行单排&#xff0c;双排&#xff0c;四人组队或单人匹配四人团队模式。在进入游戏的时候&#xff0c;玩家可以在面板选择第一人称以及第三人称。在双排或四排等组队多人游戏…

【学习】软件测试需求分析要从哪些方面入手

软件测试需求分析是软件测试过程中非常重要的一个环节&#xff0c;它是为了明确软件测试的目标、范围、资源和时间等要素&#xff0c;以确保软件测试的有效性和全面性。本文将从以下几个方面对软件测试需求分析进行详细的阐述&#xff1a; 一、软件测试目标 软件测试目标是指…

CSS文本单行溢出和多行溢出样式

一、单行溢出 1.代码 <!DOCTYPE html> <html><head><meta charset"UTF-8" /><title>demo</title><style>#div2{overflow: hidden;white-space: nowrap;/*强制不换行*/text-overflow:ellipsis;/*超出的部分用省略号代替*…

gitee和idea集成

1 集成插件 2 配置账号密码 3 直接将项目传到仓库 4直接从gitee下载项目

【Linux】有关时间的命令(date、timedatectl)

专栏文章索引&#xff1a;Linux 有问题可私聊&#xff1a;QQ&#xff1a;3375119339 目录 一、data命令 1.介绍 2.常用参数 3.常用选项 二、timedatectl命令 1.介绍 2.常用子命令 一、data命令 1.介绍 date命令用于显示或设置系统的时间与日期&#xff0c;语法格式为&a…

axios取消请求,解决接口返回顺序错乱问题

下面的方案适用于系统中的某个请求的取消&#xff0c;项目的请求使用 axios 封装 使用场景&#xff1a;当页面有多个 tab&#xff0c;例如年、月、日的列表数据&#xff0c;当点击切换的时候要获取对应的数据&#xff0c;此时如果快速点击在tab直接反复横跳会出现下面的问题&am…

java对象是怎么在jvm中new出来的,在内存中查看java对象成员变量字段属性值

java对象是怎么在jvm中new出来的 查看java对象字段属性在内存中的值 java 对象 创建 流程 附上java源码 public class MiDept {private int innerFiled999;public MiDept() {System.out.println("new MiDept--------------");}public String show(int data) {Sy…

40.Python从入门到精通—Python3 JSON 数据解析 Python3 日期和时间 什么是时间元组? 获取当前时间 获取格式化的时间

40.Python从入门到精通—Python3 JSON 数据解析 Python3 日期和时间 什么是时间元组&#xff1f; 获取当前时间 获取格式化的时间 Python3 JSON 数据解析Python3 日期和时间什么是时间元组&#xff1f;获取当前时间获取格式化的时间 Python3 JSON 数据解析 Python3 中可以使用…