代码随想录算法训练营第三十一天|动态规划:01背包理论基础、01背包理论基础(滚动数组)

news2024/11/16 3:45:16

动态规划:01背包理论基础

1. dp[i][j]: 表示0到i个物品放入容量为j的背包中,价值总和最大是多少

2. dp[i][j]的状态取决于,第i个物品要不要放入这个背包。

不放物品i:dp[i-1][j] (其实就是当物品i的重量大于背包j的重量时,物品i无法放进背包中,所以背包内的价值依然和前面相同。)

放物品i: (等于不放物品i时背包的状态加上i的价值)dp[i-1][j-weight[i]] + value[i]

取两者的最大值。

3. dp[i][j]的初始化,由上两个公式可以看出,假如dp是一个表格,dp[i][j]是由它的正上方和左上角的数字推理出来的。所以我们需要初始化第一行和第一列的值。第一列都是0(背包没有容量),第一行容量大于物品1的格子都是value【0】(背包只放物品0)。

4. 确定遍历顺序

先遍历 物品还是先遍历背包重量呢?都可以,但先遍历物品更好理解。

5. 举例推导dp数组

#include <iostream>
#include <vector>
using namespace std;

int main() {
    int n, V;
    cin>>n>>V;
    vector<int> weight(n+5);
    vector<int> value(n+5);
    for(int i=0; i<n; i++){
        cin>>weight[i];
    }
    for(int i=0; i<n; i++){
        cin>>value[i];
    }
    vector<vector<int>> dp(n, vector<int>(V+1, 0));//bagweight V需要加一
    for(int i = weight[0]; i <= V; i++){
        dp[0][i] = value[0];
    }
    for(int i=1; i<n; i++){
        for(int j=0; j<=V; j++){//从0到V一共V+1个不同重量
            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]);
        }
    }
    cout<<dp[n-1][V]<<endl;
    return 0;
}

01背包理论基础(滚动数组)

其实可以发现如果把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](一维数组,也可以理解是一个滚动数组)。

1. dp[j] 容量为j的背包能放下多少价值的东西。

2. 一维dp数组的递推公式:此时dp[j]有两个选择,一个是取自己dp[j] 相当于 二维dp数组中的dp[i-1][j],即不放物品i,一个是取dp[j - weight[i]] + value[i],即放物品i,指定是取最大的,毕竟是求最大价值。

dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);

3. 一维dp数组如何初始化:初始为0

4. 一维dp数组遍历顺序:

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]);

    }
}

二维dp遍历的时候,背包容量是从小到大,而一维dp遍历的时候,背包是从大到小。

倒序遍历是为了保证物品i只被放入一次!

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

    // 初始化
    vector<int> dp(bagWeight + 1, 0);
    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]);
        }
    }
    cout << dp[bagWeight] << endl;
}

int main() {
    test_1_wei_bag_problem();
}

所以我倾向于使用一维dp数组的写法,比较直观简洁,而且空间复杂度还降了一个数量级!

在后面背包问题的讲解中,我都直接使用一维dp数组来进行推导

416. 分割等和子集

给定一个只包含正整数的非空数组。是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。

只有确定了如下四点,才能把01背包问题套到本题上来。

  • 背包的体积为sum / 2
  • 背包要放入的商品(集合里的元素)重量为 元素的数值,价值也为元素的数值
  • 背包如果正好装满,说明找到了总和为 sum / 2 的子集。
  • 背包中每一个元素是不可重复放入

1. dp[j]的含义:dp[j]表示 背包总容量(所能装的总重量)是j,放进物品后,背的最大重量为dp[j]

2. 递推公式:01背包的递推公式为:dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);

3. 初始化:dp[0]一定是0。如果题目给的价值都是正整数那么非0下标都初始化为0就可以了,如果题目给的价值有负数,那么非0下标就要初始化为负无穷。

4. 确定遍历顺序:如果使用一维dp数组,物品遍历的for循环放在外层,遍历背包的for循环放在内层,且内层for循环倒序遍历!

5. 举例推导dp数组

class Solution {
public:
    bool canPartition(vector<int>& nums) {
        int sum=0;
        vector<int> dp(10005, 0);
        for(int i=0; i<nums.size(); i++){
            sum+=nums[i];
        }
        if(sum%2==1) return false;
        int target = sum/2;
        for(int i=0; i<nums.size(); i++){
            for(int j=target; j>=nums[i]; j--){
                dp[j] = max(dp[j-nums[i]]+nums[i], dp[j]);
            }
        }
        if(dp[target]==target) return true;
        return false;
    }
};
  • 时间复杂度:O(n^2)
  • 空间复杂度:O(n),虽然dp数组大小为一个常数,但是大常数

题目中物品是nums[i],重量是nums[i],价值也是nums[i],背包体积是sum/2。

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

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

相关文章

Golang | Leetcode Golang题解之第229题多数元素II

题目&#xff1a; 题解&#xff1a; func majorityElement(nums []int) (ans []int) {cnt : map[int]int{}for _, v : range nums {cnt[v]}for v, c : range cnt {if c > len(nums)/3 {ans append(ans, v)}}return }

Mediapipe-姿态估计实例

Mediapipe简介 Mediapipe 是由 Google Research 开发的一款开源框架&#xff0c;旨在帮助开发者轻松地构建、测试和部署复杂的多模态、多任务的机器学习模型。它特别擅长于实时处理和分析音频、视频等多媒体数据。以下是 Mediapipe 的一些关键特点和组件&#xff1a; 关键特点…

【Unity2D 2022:UI】制作主菜单

一、创建主菜单游戏场景 1. 在Scenes文件夹中新建一个游戏场景Main Menu 2. 为场景添加背景 &#xff08;1&#xff09;创建画布Canvas &#xff08;2&#xff09;在Canvas中创建新的空游戏物体Main Menu &#xff08;3&#xff09;在Main Menu中新建一个图像游戏物体Backgrou…

Java项目中,常用的SQL语句

常用的命令&#xff1a; 1.数据的增删改查 1.插入数据(进行注册&#xff09; 语法 1&#xff1a; --第一种&#xff1a; INSERT INTO 表名(列名 1,列名 2, …) ; insert into tablename(member1,member3) valuse(,); --第二种&#xff1a; INSERT INTO 表名 VALUES(值 1,值 …

Linux工具篇:yum

前言&#xff1a; 目录 前言&#xff1a; Linux 软件包管理器 yum yum是什么&#xff1f; 什么是软件包&#xff1f; Linux系统&#xff08;centos&#xff09;的生态&#xff1a; 那我的yum是怎么找到对应的软件呢&#xff1f; 关于 rzsz yum查看软件包&#xff08;安装…

Python task

def wordcount(text):# 将文本分割成单词列表&#xff0c;并转换为小写words text.lower().split()# 初始化一个空字典用于存储单词计数word_counts {}# 遍历单词列表中的每个单词for word in words:# 如果单词在字典中&#xff0c;则计数加1&#xff0c;否则将单词加入字典并…

配置sublime的中的C++编译器(.sublime-build),实现C++20在sublime中的使用,小白教程

一&#xff0c;前期准备 首先我们需要准备一下 C 环境&#xff0c;当然如果你觉得你当前的C环境配置好了&#xff0c;并且C的版本也能完成您日常的使用需求&#xff0c;您可以使用下面两条命令对C的版本进行查询 g -vg --version通过返回的版本简单的判断是否能解决您的需求&…

Delta的最新更新可让iPad用户同时模拟多款游戏

Delta iOS 应用程序发布了一个更新&#xff0c;引入了复古 游戏模拟器重新设计的标识&#xff0c;以及原生 iPad 支持&#xff0c;允许用户同时玩多个 游戏。 据 Delta 开发者 Riley Testut 称&#xff0c;欧盟用户可以立即通过AltStore PAL 下载更新&#xff0c;但其他用户则需…

Tomcat多实例

一、Tomcat多实例 Tomcat多实例是指在同一台服务器上运行多个独立的tomcat实例&#xff0c;每个tomcat实例都具有独立的配置文件、日志文件、应用程序和端口&#xff0c;通过配置不同的端口和文件目录&#xff0c;可以实现同时运行多个独立的Tomcat服务器&#xff0c;每个服务…

成为编程大佬!!----->数据结构与算法(2)——顺序表!!

前言&#xff1a;线性表是数据结构与算法的重中之重&#xff0c;所有具有线性逻辑结构的数据结构&#xff0c;都能称为线性表。这篇文章我们先来讨论线性表中的顺序表&#xff0c;顺序表和线性表都是后续实现栈&#xff0c;树&#xff0c;串和图等等结构的重要基础。 目录 ❀简…

YOLOv10改进 | 主干/Backbone篇 | 轻量级网络ShuffleNetV1(附代码+修改教程)

一、本文内容 本文给大家带来的改进内容是ShuffleNetV1&#xff0c;这是一种为移动设备设计的高效CNN架构。它通过使用点群卷积和通道混洗等操作&#xff0c;减少了计算成本&#xff0c;同时保持了准确性&#xff0c;通过这些技术&#xff0c;ShuffleNet在降低计算复杂度的同时…

yolov8、RTDETR无法使用多个GPU训练

yolov8、RTDETR无法使用多个GPU训练 网上看了好多解决方法&#xff1a; 什么命令行 CUDA_VISIBLE_DEVICES0,1 python train.py 环境变量都不行 最后找到解决方案&#xff1a;在ultralytics/engine/trainer.py 中的第246行 将 self.model DDP(self.model, device_ids[RANK])…

Web 应用程序开发的前沿:2024 年会发生什么??

Web 应用程序开发是发展最快的领域之一&#xff0c;令人印象深刻地改变了网络空间的给定面貌。 随着我们进入 2024 年&#xff0c;许多进步趋势和技术正在出现&#xff0c;它们整合了开发人员和商人探索他们才能的新领域。 这篇博客将介绍有关创建 Web 应用程序的最新趋势的想法…

记一次若依框架和Springboot常见报错的实战漏洞挖掘

目录 前言 本次测实战利用图​ 1.判段系统框架 2.登录页面功能点测试 2.1 弱口令 2.2 webpack泄露信息判断 2.3 未授权接口信息发现 3.进一步测试发现新的若依测试点 3.1 默认弱口令 3.2 历史漏洞 4.访问8080端口发现spring经典爆粗 4.1 druid弱口令 4.2 SwaggerU…

牛顿力学和拉格朗日力学求解atwood machine问题对比

一个半径为 R R R、转动惯量为 I I I 的圆盘。绳子与圆盘无滑动&#xff0c;质量 m 2 m_2 m2​ 的物体在重力 g g g 作用下下坠&#xff0c;带动质量 m 1 m_1 m1​ 的物体上升。求 m 1 m_1 m1​和 m 2 m_2 m2​ 的加速度 a a a。 牛顿力学方法 对质量 m 1 m_1 m1​ 和 …

攻防世界(PHP过滤器过滤)file_include

转换过滤器官方文档&#xff1a;https://www.php.net/manual/zh/filters.convert.php#filters.convert.iconv 这道题因为convert.base64-encode被过滤掉了&#xff0c;所以使用convert.iconv.*过滤器 在激活 iconv 的前提下可以使用 convert.iconv.* 压缩过滤器&#xff0c; 等…

Jmeter多用户登录操作实战

在使用Jmeter性能测试时,首先要解决的问题恐怕就会并发压测和多用登录的问题.今天就一篇文章讲清楚这两个问题的解决方案: 一.多并发压测如何配置线程? &#xff08;1&#xff09;同时并发&#xff1a;设置线程组、执行时间、循环次数&#xff0c;这种方式可以控制接口请求的…

Axure-黑马

Axure-黑马 编辑时间2024/7/12 来源&#xff1a;B站黑马程序员 需求其他根据&#xff1a;visio&#xff0c;墨刀 Axure介绍 Axure RP是美国Axure Software Solution给公司出品的一款快速原型大的软件&#xff0c;一般来说使用者会称他为Axure 应用场景 拉投资使用 给项目团…

(自用)高并发实现高效内存管理

高并发下传统方式的弊端 C语言常用的内存操作函数 C下采用new进行内存分配&#xff0c;delete进行内存释放。 弊端一 分配内存需要进入内核态&#xff0c;总分配大小不变的情况下&#xff0c;多次分配较小的内存导致了变态频繁&#xff0c;降低系统效率. 弊端二 弊端三 情形…

LayoutLMv2:视觉丰富文档理解的多模态预训练

文本和布局的预训练由于其有效的模型架构和大规模未标记扫描/数字出生文档的优势&#xff0c;在各种视觉丰富的文档理解任务中被证明是有效的。我们提出了具有新的预训练任务的LayoutLMv2架构&#xff0c;以在单个多模态框架中对文本、布局和图像之间的交互进行建模。具体而言&…