01背包问题详解

news2024/9/29 1:23:32

目录

1.1二维dp数组

1.2一维dp数组改进

1.3相关例题

1.3.1分割等和子集

1.3.2一和零


1.1二维dp数组

概述:背包的最大重量是固定的,物品的数量,重量也是固定的,并且物品只能放一次,可以选择放或者不放,最后要保证背包里面物品的最大价值。

例如:下面假设背包的最大重量是4.

 解释:dp[i][j]的含义:从下标为[0-i]的物品里任意取,放进容量为j的背包,价值总和最大是多少。

可以从两个方向去推导dp[i][j],放当前物品或者不放当前物品。

由dp[i - 1][j]推出,即背包容量为j,里面不放物品i的最大价值,此时dp[i][j]就是dp[i - 1][j]
由dp[i - 1][j - weight[i]]推出,dp[i - 1][j - weight[i]] 为背包容量为j - weight[i]且不放物品i的最大价值,那么dp[i - 1][j - weight[i]] + value[i] (物品i的价值),就是背包放物品i得到的最大价值,所以递归公式: dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);

开辟一个二维数组

 当背包的容量为0和物品数量为0时,背包的价值都是0.

 可以尝试先遍历物,1,可以认为当前只有一个物品,背包的容量为1-4,后面在去遍历物品2,背包的容量也是从1-4。例如:

 完整代码:

vector<int> weight = { 1, 3, 4 };
vector<int> value = { 15, 20, 30 };
int bagWeight = 4;

// 二维数组,全初始化为0
vector<vector<int>> dp(weight.size() + 1, vector<int>(bagWeight + 1, 0))

// weight数组的大小 就是物品个数
for (int i = 1; i < weight.size(); i++)
{ // 遍历物品
    for (int j = 0; j <= bagWeight; j++)
    { // 遍历背包容量
        if (j < weight[i])
            dp[i][j] = dp[i - 1][j];
        else 
            dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);

    }
}

1.2一维dp数组改进

思路:

在使用二维数组的时候,递推公式:dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);

其实可以发现如果把dp[i - 1]那一层拷贝到dp[i]上,表达式完全可以是:dp[i][j] = max(dp[i][j], dp[i][j - weight[i]] + value[i]);把dp[i - 1]这一层拷贝到dp[i]上,不如只用一个一维数组了,只用dp[j](一维数组,也可以理解是一个滚动数组)。

确定dp数组的定义:
在一维dp数组中,dp[j]表示:容量为j的背包,所背的物品价值可以最大为dp[j]。

一维dp数组的递推公式

dp[j]可以通过dp[j - weight[j]]推导出来,dp[j - weight[i]]表示容量为j - weight[i]的背包所背的最大价值。dp[j - weight[i]] + value[i] 表示 容量为 j - 物品i重量 的背包 加上 物品i的价值。(也就是容量为j的背包,放入物品i了之后的价值)

dp[j]有两个选择,一个是取自己dp[j],一个是取dp[j - weight[i]] + value[i],取最大值,递归公式为:dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);

假设也是先遍历物品,再去遍历背包。

例如:

 在一维数组中,为了确保每个物品只能放入一次,遍历背包时,应该先去遍历背包的容量。例如:

 代码:

for (int i = 0; i < weight.size(); i++) // 遍历物品
{                                 
    for (int j = bagWeight; j >= weight[i]; j--) 
   {
        dp[j] = max(dp[j], dp[j - weight[i]] + value[i]); // 遍历背包容量

    }
}

1.3相关例题

1.3.1分割等和子集

问题描述:给你一个 只包含正整数 的 非空 数组 nums 。请你判断是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。

输入:nums = [1,5,11,5]
输出:true
解释:数组可以分割成 [1, 5, 5] 和 [11] 。

思路:使这两个子集的元素相等,也就是让子集的和为数组和的一半。其实可以认为子集和就是背包的最大容量,也是最大价值。问题等效于能否从数组中挑选若干个元素,使得元素总和等于所有元素总和的一半。也就是判断该背包装满后,最大容量装满后的价值是否恰好等于最大价值。

代码示例:

class Solution {
public:
    bool canPartition(vector<int>& nums) {
        int sum=0;
        for(int i=0;i<nums.size();i++)
          sum+=nums[i];
        if(sum%2!=0)
         return false;
        sum/=2;
        vector<vector<int>>dp(nums.size()+1,vector<int>(sum+1,0));
        for(int i=1;i<=nums.size();i++)
        {
            for(int j=1;j<=sum;j++)   //nums[i-1]为第i个物品
            {
                if(j<nums[i-1])  
                 dp[i][j]=dp[i-1][j];
                else
                dp[i][j]=max(dp[i-1][j],dp[i-1][j-nums[i-1]]+nums[i-1]);
            }
        }
        if(dp[nums.size()][sum]==sum)
         return true;
        return false;

    }
};

一维dp数组改进:

class Solution {
public:
    bool canPartition(vector<int>& nums) {
        int sum = 0;
        for (int i = 0; i < nums.size(); i++)
        {
            sum += nums[i];
        }
        if (sum % 2 == 1) return false;
        int target = sum / 2;
        vector<int> dp(target + 1, 0);
        // 开始 01背包
        for (int i = 0; i < nums.size(); i++) 
        {
            for (int j = target; j >= nums[i]; j--) 
            { 
                dp[j] = max(dp[j], dp[j - nums[i]] + nums[i]);
            }
        }
        if (dp[target] == target)
            return true;
        return false;
    }
};

1.3.2一和零

问题描述:

给你一个二进制字符串数组 strs 和两个整数 m 和 n 。

请你找出并返回 strs 的最大子集的长度,该子集中 最多 有 m 个 0 和 n 个 1 。

如果 x 的所有元素也是 y 的元素,集合 x 是集合 y 的 子集 。

输入:strs = ["10", "0001", "111001", "1", "0"], m = 5, n = 3
输出:4
解释:最多有 5 个 0 和 3 个 1 的最大子集是 {"10","0001","1","0"} ,因此答案是 4 。
其他满足题意但较小的子集包括 {"0001","1"} 和 {"10","1","0"} 。{"111001"} 不满足题意,因为它含 4 个 1 ,大于 n 的值 3 。

这也是一道01背包问题,元素的个数是确定的,背包的容量也是确定的,只不过该背包的容量有两个维度罢了。本质就是求背包放满后,可以放入的元素个数最多是多少。

class Solution {
public:
    int findMaxForm(vector<string>& strs, int m, int n) {//m个0,n个1
   
    vector<vector<int>> v(m+1,vector<int>(n+1,0));
   for(auto s:strs)
   {  int p1=0;
      int p0=0;
       for(auto ch: s)   //先遍历物品
       {
           if(ch=='0')
            p0++;
           else
           p1++;
       }                 
       for(int i=1;i<=m;i++) /后遍历背包容量,背包容量,用一个二维数组表示
       {
           for(int j=1;j<=n;j++)
           {
               if(i>p0&&j>p1)  //说明能放下该物品
               {
                   v[i][j]=max(v[i][j],v[i-p0][j-p1]+1);
               }
           }
       }
   }
   return v[m][n];
        
    }
};

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

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

相关文章

Redis 核心原理串讲(中),架构演进之高可用

文章目录Redis 核心原理总览&#xff08;全局篇&#xff09;前言一、持久化1、RDB2、AOF3、AOF 重写4、混合持久化5、对比二、副本1、同步模式2、部分重同步三、哨兵1、核心能力2、节点通信总结Redis 核心原理总览&#xff08;全局篇&#xff09; 正文开始之前&#xff0c;我们…

【FPGA】Verilog:基本实验步骤演示 | 功能电路创建 | 添加仿真激励 | 观察记录仿真波形

前言&#xff1a; 本章内容主要是演示Vivado下利用Verilog语言进行电路设计、仿真、综合和下载的完整过程、Verilog语言基本运用&#xff0c;电路设计和Test Bench程序的编写、以及实验开发板的使用&#xff0c;通过观察和数据记录理解仿真和FGPA实现的差异。 目录 Ⅰ. 基础知…

考研政治 马原 易混淆知识点

马哲 1. 哲学基本问题 从何者为第一性&#xff0c;分为唯物主义和唯心主义 从是否具有同一性&#xff0c;分为可知论&#xff08;有同一性&#xff09;和不可知论&#xff08;无同一性&#xff09; 辩证法&#xff1a;联系&#xff0c;发展的观点看世界&#xff0c;认为发展的…

python对接API二次开发高级实战案例解析:百度地图Web服务API封装函数(行政区划区域检索、地理编码、国内天气查询、IP定位、坐标转换)

文章目录前言一、IP定位1.请求URL2.获取IP定位封装函数3.输出结果二、国内天气查询1.请求url2.天气查询封装函数3.输出结果三、行政区划区域检索1.请求url2.区域检索封装函数3.输出结果四、地理编码1.请求url2.地理编码封装函数3.输出结果五、坐标转换1.请求url2.坐标转换封装函…

一文细说Linux虚拟文件系统原理

在 Unix 的世界里&#xff0c;有句很经典的话&#xff1a;一切对象皆是文件。这句话的意思是说&#xff0c;可以将 Unix 操作系统中所有的对象都当成文件&#xff0c;然后使用操作文件的接口来操作它们。Linux 作为一个类 Unix 操作系统&#xff0c;也努力实现这个目标。 虚拟…

CSS 这个就叫优雅 | 多行文本溢出省略

CSS 这个就叫优雅 | 多行文本溢出省略 文章目录CSS 这个就叫优雅 | 多行文本溢出省略一、文本溢出省略方式二、WebKit内核浏览器解决方法&#x1f959;三、通用解决方法四、CSS 预处理器封装&#x1f969;五、参考资料&#x1f498;六、推荐博文&#x1f357;一、文本溢出省略方…

小样本学习(Few-Shot Learning)训练参数意义

一、常规参数 1.1 epoch 是指所有的训练数据都要跑一遍。假设有6400个样本&#xff0c;在训练过程中&#xff0c;这6400个样本都跑完了才算一个epoch。一般实验需要训练很多个epoch&#xff0c;直到LOSS稳定后才停止。 1.2 batch_size 中文名称是批大小&#xff0c;之前的640…

【数据结构趣味多】二叉树概念及性质

1.树的定义 定义&#xff1a;树&#xff08;Tree&#xff09;是n&#xff08;n>0&#xff09;个结点的有限集。n0时称为空树。在任意一棵非空树种&#xff1b; 有且仅有一个根结点&#xff08;root&#xff09;。当n>1时&#xff0c;其余结点可分为m&#xff08;m>0&a…

H13-531云计算HCIE V2.0——400~600常错题和知识点总结

400~600 422、在 FusionCloud 6.x 中&#xff0c;以下关于备份的说法哪项是错误的&#xff1f; A&#xff0e;备份协议支持本地&#xff0c;通过 FTP/SFTP 到第三方服务器及 OBS B. 为了保证系统稳定运行&#xff0c;对管理数据进行备份恢复可以确保在异常时对业务的影响降到…

没有完美的项目,也轮不到你,找到适合自己的,先干起来再说

首先明确一点&#xff0c;没有百分百完美的项目&#xff0c;即使有&#xff0c;也轮不到你。不要认为你必须先找到一个完美的项目&#xff0c;然后再去工作。这个想法最后的结局就是项目一直在找&#xff0c;观望&#xff0c;迟迟不行动&#xff0c;不赚钱。如果你真的想找个项…

C++ 语法基础课 习题7 —— 类、结构体、指针、引用

文章目录例题1. 21.斐波那契数列2. 16.替换空格3. 84.123...n4. 28.O(1)时间删除链表结点5. 36.合并两个排序的链表例题 1. 21.斐波那契数列 Acwing 21.斐波那契数列 class Solution { public:int Fibonacci(int n) {if(n < 1) return n;return Fibonacci(n - 1) Fibon…

并发编程 - ThreadLocal

前言 ThreadLocal 用于解决多线程对于共享变量的访问带来的安全性问题。ThreadLocal 存储线程局部变量。每个线程内置 ThreadLocalMap&#xff0c;ThreadLocalMap 的 key 存储 ThreadLocal 实例&#xff0c;value 存储自定义的值。与同步机制相比&#xff0c;它是一种“空间换…

vue性能优化之预渲染prerender-spa-plugin+vue-meta-info解决seo问题

单页面应用中&#xff0c;web项目只有一个页面&#xff0c;前端根据路由不同进行组件之间的对应切换&#xff0c;动态的渲染页面内容。这就是客户端渲染&#xff0c;具有减少服务器端压力、响应速度快等优点。但是单页应用在优化用户体验的同时&#xff0c;也给我们带来了一些对…

阅读 | 001《人工智能导论》(三)知识应用篇1

文章目录知识应用第9章、专家系统9.1 专家系统概述9.2 推理方法9.3 一个简单的专家系统9.4 非确定性推理9.5 专家系统工具9.6 专家系统的应用9.7 专家系统的局限性9.8 本章小结第10章、计算机视觉10.1 计算机视觉概述10.2 数字图像的类型及机内表示10.3 常用计算机视觉模型和关…

计算机重装系统方法教程

​计算机在使用的过程中出现各种问题也是在所难免的&#xff0c;当计算机出现了一些系统故障问题没有办法解决时&#xff0c;或是计算机使用长了以后运行就会变得越来越慢时&#xff0c;这时大家可以考虑通过电脑重装系统来解决&#xff0c;那么&#xff0c;计算机如何重装系统…

ArcGIS基础实验操作100例--实验71多图层叠加查询

本实验专栏参考自汤国安教授《地理信息系统基础实验操作100例》一书 实验平台&#xff1a;ArcGIS 10.6 实验数据&#xff1a;请访问实验1&#xff08;传送门&#xff09; 高级编辑篇--实验71 多图层叠加查询 目录 一、实验背景 二、实验数据 三、实验步骤 &#xff08;1&am…

MATLAB——PCM编译码实验

目录MATLAB——PCM编译码一、实验原理1.掌握PCM编码原理和译码原理2. 练习使用Matlab编程实现PCM编码和译码3. 了解失真度的概念&#xff0c;能对译码结果进行失真度分析二、实验原理三、实验要求1、用Matlab产生一模拟信号&#xff0c;如&#xff1a; 或者自己编写一信号&…

“微综艺+虚拟场景”,蓝海创意云利用元宇宙技术撬动流量杠杆

1月1日&#xff0c;抖音微综艺节目“友问必答”2023新年直播盛大开幕&#xff0c;蓝海创意云利用vLive虚拟直播系统为此档节目搭建了专属的“元宇宙问答直播间”&#xff0c;整场直播观看人次突破 30W 人次&#xff0c;最高同时在线人数达 3W 人次&#xff0c;独特的直播形式和…

基于Spring+Mybatis框架的人事管理系统源码+数据库,含视频部署教程

人事管理系统 下载地址&#xff1a;基于SpringMybatis框架的人事管理系统源码数据库 部署说明&#xff1a; 项目启动后&#xff0c;在浏览器中访问地址&#xff1a;http://127.0.0.1:8080/personnel/ 由于很多同学反映部署有问题&#xff0c;所以我录了一个视频来演示一下&…

【Python爬虫项目实战】Python爬虫采集某外包平台数据保存本地

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录前言一、开发工具二、环境搭建三、数据来源查询分析四、代码实现1. 发送请求2.数据获取3.解析数据4. 保存数据总结前言 今天给大家介绍的是Python爬虫某外包平台数据…