代码随想录算法训练营第三十天| 01背包问题 二维, 01背包问题 一维 , 416. 分割等和子集

news2024/11/15 12:33:10

今天是动态规划学习的第三天,主要的学习内容包括:01背包问题二维数组解法和一维数组解法,以及01背包问题的应用。

 01背包问题 二维

题目链接:46. 携带研究材料(第六期模拟笔试) (kamacoder.com)

首先我们需要了解什么是01背包问题。有n件物品和容量为w的书包,第i件物品的质量为w[i],价值为val[i],每个物品只能使用一次,求解将哪些物品装入背包可以获得最大的价值。

首先对于dp[i][j],我们定义为0-i件物品在背包容量为j时的最大价值,如下图所示:

对于递推公式,我们有两种情况:当我们不放入物品i时,我们的dp[i][j]应该是等于dp[i-1][j]的;当我们需要放入物品i时,应该减少书包的容量,并增加i的价值,所以dp[i][j]=dp[i-1][j-w[i]]+val[i];我们需要在这两种情况中选择价值较大的情况。 

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

对于初始化,我们需要把第一列初始化为0,因为背包容量为0时肯定啥都装不了;我们需要把第一行的j>=w[0]的情况置为val[0],即当背包容量大于等于第一件物品的质量时,就装入第一件物品;装不下第一件物品就将其赋值为0.

对于遍历顺序,既可以先遍历物品,再遍历背包容量;也可以先遍历背包容量,再便利物品。因为我们dp[i][j]的更新取决于左上角的数值,而这两种遍历方式都会优先把左上角进行赋值,所以在求解时都是可行的。

具体代码实现如下所示:
 

#include<iostream>
#include<vector> 
using namespace std;
int main()
{
    int n;
    int bagweight;
    scanf("%d%d",&n,&bagweight);
    vector<int> weight(n,0);
    vector<int> value(n,0);
    for(int i=0;i<n;i++) scanf("%d",&weight[i]);
    for(int i=0;i<n;i++) scanf("%d",&value[i]);
    vector<vector<int>> dp(n,vector<int>(bagweight + 1, 0));
    for(int i=weight[0];i<=bagweight;i++)
    {
         dp[0][i]=value[0];
    }
    for(int i=1;i<n;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]);
        }
    }
    printf("%d",dp[n-1][bagweight]);
     
}

01背包问题 一维

题目链接:46. 携带研究材料(第六期模拟笔试) (kamacoder.com)

对于01背包问题,我们也可以对二维数组进行状态压缩,从而使用一维数组解决01背包问题。

首页是dp[j]的含义,我们定义为在背包容量最大为j时的最大价值。

对于递推公式,还是分成那两种情况,当不装入物品时,dp[j]=dp[j];当装入物品时,dp[j]=dp[j-w[i]]+val[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]);

    }
}

首先,我们先来讲一下为什么内层循环一定要倒序遍历。因为我们其实是将二维数组压缩到一维数组内,假如我们正序遍历,物品就会被多次放入。举个例子,假如w[0]=1,val[0]=15,那么dp[0]=0;

dp[1]=dp[1-w[0]]+val[0]=15,dp[2]=dp[2-w[0]]+15=dp[1]+15=30.在这个例子中,物品0就已经被重复添加了。因为在这个过程中,我们更新所用到的数值已经在前面的更新过程中更新过了。可以理解为我们是将二维数组一行一行的赋值到一维数组内,然而更新时已经用到了前面更新的值,这当然会出现问题。所以我们只能逆序遍历来保证物品只会被使用一次。

接下来我们讨论一下能否将外层循环和内层循环的顺序颠倒,答案也是不行的。假如把顺序颠倒,将背包容量的便利放在外面,就意味着每个包只放入了最大价值的一个物品。这显然也是不符合我们的要求的。所以只能物品在外循环,背包容量在内循环。

具体代码实现如下所示:
 

#include<iostream>
#include<vector> 
using namespace std;
int main()
{
    int n;
    int bagweight;
    scanf("%d%d",&n,&bagweight);
    vector<int> weight(n+1,0);
    vector<int> value(n+1,0);
    for(int i=0;i<n;i++) scanf("%d",&weight[i]);
    for(int i=0;i<n;i++) scanf("%d",&value[i]);
    vector<int> dp(bagweight+5,0);
    for(int i=0;i<n;i++)
    {
        for(int j=bagweight;j>=weight[i];j--)
        {
             dp[j]=max(dp[j],dp[j-weight[i]]+value[i]);
        }
    }
    printf("%d",dp[bagweight]);
    
}

416. 分割等和子集

题目链接:416. 分割等和子集 - 力扣(LeetCode)

我一开始其实是想暴力递归的,然后就超时了。所以使用动态规划进行求解。

我们将其带入背包问题,数组的元素值既是重量又是价值,背包容量是sum/2,物品的遍历是0-n,如果dp[sum/2]==sum/2,就说明是可以满足条件的,否则返回false。具体代码实现如下所示:
 

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);
        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;
        else return false;
    }
};

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

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

相关文章

胡姓名人伟人有哪些?胡姓最厉害三个名人是谁

胡姓名人伟人有哪些?胡姓最厉害三个名人是谁? 在中国悠久的历史长河中,胡姓不仅承载着丰富的文化遗产,更是孕育出无数杰出的历史人物。这些人物以其独特的贡献和影响力,成为中华文明的重要组成部分。以下是根据历史影响力和文化贡献精心挑选的十大胡姓名人,他们的故事和成就展…

GNU/Linux - systemd介绍

systemd官网&#xff1a; System and Service Manager systemd systemd Github地址&#xff1a; https://github.com/systemd/systemd 首次发布 2010年3月30日 System and Service Manager systemd 是一套 Linux 系统的基本构件。它提供了一个系统和服务管理器&#xff0c;作为…

USB 2.0 协议专栏之 USB 配置描述符(四)

前言&#xff1a;本篇博客为手把手教学的 USB 2.0 协议栈类精品博客&#xff0c;该专栏博客侧重针对 USB 2.0 协议进行讲解。第 4 篇重点为 USB 2.0 协议中的配置描述符 Configuration Descriptors 进行讲解&#xff0c;并结合 CH32V307 与 STM32 代码进行 Configuration Descr…

【工业机器人】工业异常检测大模型AnomalyGPT

AnomalyGPT 工业异常检测视觉大模型AnomalyGPT AnomalyGPT: Detecting Industrial Anomalies using Large Vision-Language Models AnomalyGPT是一种基于大视觉语言模型&#xff08;LVLM&#xff09;的新型工业异常检测&#xff08;IAD&#xff09;方法。它利用LVLM的能力来理…

Oracle VM VirtualBox虚拟机内存不够用的解决方案

一、 前言 在使用Oracle VM VirtualBox虚拟机的过程中&#xff0c;随着时间的推移&#xff0c;我们会感觉我们的内存越来越不够用&#xff0c;今天就来给大家分享一下我们如何解决虚拟机内存不够用的问题。 二、解决方法 1.虚拟机碎片化整理 我们第一步要做的是碎片整理&…

【protobuf】ProtoBuf——proto3语法详解、enum类型、enum类型的使用和注意事项、Any类型、通讯录录入号码类型和地址的功能实现

文章目录 ProtoBuf5. proto3语法详解5.3 enum类型5.4 Any类型 ProtoBuf 5. proto3语法详解 5.3 enum类型 定义规则&#xff1a; proto3支持我们定义枚举类型并使用&#xff1a; 枚举类型的名称采用驼峰命名法且首字母大写&#xff0c;如 MyEnum &#xff0c;这样的命名方式符合…

重启人生计划-且随风行

&#x1f973;&#x1f973;&#x1f973; 茫茫人海千千万万&#xff0c;感谢这一刻你看到了我的文章&#xff0c;感谢观赏&#xff0c;大家好呀&#xff0c;我是最爱吃鱼罐头&#xff0c;大家可以叫鱼罐头呦~&#x1f973;&#x1f973;&#x1f973; 如果你觉得这个【重启人生…

Element UI详解

目录 Element UIElement UI 简介开发使用开发指南概述总结 设计原则组件使用特性使用场景优势不足 Element UI Element UI 简介 Element UI 是由饿了么前端团队开发的一套基于 Vue.js 的桌面端组件库。它提供了一系列丰富的 UI 组件&#xff0c;用于快速搭建企业级的 Web 应用…

RCE编码绕过--php://filter妙用

目录 代码 如何绕过 payload构造 代码 <?php $content <?php exit; ?>; $content . $_POST[txt]; file_put_contents($_POST[filename],$content); 当你想要输入代码的时候前面会有<?php exit;?>;&#xff0c;代码没有办法执行下去&#xff0c;所以…

day32+学习记录

一.算法练习 509.斐波那契数 斐波那契数 &#xff08;通常用 F(n) 表示&#xff09;形成的序列称为 斐波那契数列 。该数列由 0 和 1 开始&#xff0c;后面的每一项数字都是前面两项数字的和。也就是&#xff1a; F(0) 0&#xff0c;F(1) 1 F(n) F(n - 1) F(n - 2)&#xf…

(待会删)分享9款一键生成原创论文在线使用软件

在当前的学术研究和写作环境中&#xff0c;AI技术的应用已经变得越来越普遍。其中&#xff0c;一键生成原创论文的在线软件更是为学者们提供了极大的便利。本文将重点介绍一款备受推荐的AI原创论文写作平台——千笔-AIPassPaPer&#xff0c;并分享其他几款优秀的同类软件。 千…

政务大数据解决方案(五)

政务大数据解决方案旨在通过建立统一的数据平台&#xff0c;将各政府部门的数据资源进行有效整合与智能分析&#xff0c;利用先进的数据处理和人工智能技术实现对社会动态的实时监测和精准预测&#xff0c;从而优化政府决策、提升公共服务效率和透明度。该方案涵盖数据的采集、…

每日OJ_牛客HJ75 公共子串计算

目录 牛客HJ75 公共子串计算 解析代码 牛客HJ75 公共子串计算 公共子串计算_牛客题霸_牛客网 解析代码 求最大公共子串&#xff0c;使用递推实现 假设 x(i)&#xff1a;字符串第i个字符 y(j)&#xff1a;字符串第j个字符 dp[i][j]&#xff1a;以x(i)&#xff0c;y(j)结尾的最…

XSS-games

XSS 1.XSS 漏洞简介2.XSS的原理3.XSS的攻击方式4.XSS-GAMESMa SpaghetJefffUgandan KnucklesRicardo MilosAh Thats HawtLigmaMafiaOk, BoomerWW3svg 1.XSS 漏洞简介 ​ XSS又叫CSS&#xff08;Cross Site Script&#xff09;跨站脚本攻击是指恶意攻击者往Web页面里插入恶意Sc…

XSS反射实战

目录 1.XSS向量编码 2.xss靶场训练&#xff08;easy&#xff09; 2.1第一关 2.2第二关 方法一 方法二 2.3第三关 2.4第四关 2.5第五关 2.6第六关 2.7第七关 第一种方法&#xff1a; 第二种方法&#xff1a; 第三个方法&#xff1a; 2.8第八关 1.XSS向量编码 &…

二叉树进阶之二叉搜索树:一切的根源

前言&#xff1a; 在学完了简单的容器与C面向对象的三大特性之后&#xff0c;我们首先接触的就是map与set两大容器&#xff0c;但是这两个容器底层实现的原理是什么呢&#xff1f;我们不而知&#xff0c;今天&#xff0c;主要来为学习map与set的底层原理而打好基础&#xff0c…

【精选】学生考勤管理系统设计与实现(源码+辅导+设计)

目录&#xff1a; 系统介绍&#xff1a; 第2章 开发技术介绍 2.1 B/S结构 2.2 Java语言 2.3 springboot框架 2.4 MySQL数据库 系统设计 系统的总体功能设计 系统实现界面&#xff1a; 3.视频演示 系统测试 测试概述 测试结果 参考代码&#xff1a; 为什么选择我&am…

【数据结构】PTA 单链表逆转 C语言

本题要求实现一个函数&#xff0c;将给定的单链表逆转。 函数接口定义&#xff1a; List Reverse( List L ); 其中List结构定义如下&#xff1a; typedef struct Node *PtrToNode; struct Node {ElementType Data; /* 存储结点数据 */PtrToNode Next; /* 指向下一个结点的…

进程间通信学习记录(IPC 机制以及共享内存)

0.System V IPC机制&#xff1a; ①.IPC对象包含&#xff1a;共享内存、消息队列和信号灯集。 ②.每个IPC对象有唯一的ID。 ③.IPC对象创建后一直存在&#xff0c;直到被显示地删除。 ④.每一个IPC对象有一个关联的KEY。&#xff08;其他进程通过KEY访问对应的IPC对象&#xff…

XSS和DOM破坏案例

XSS案例 环境地址&#xff1a;XSS Game - Learning XSS Made Simple! | Created by PwnFunction 1.Ma Spaghet! 源码&#xff1a; <!-- Challenge --> <h2 id"spaghet"></h2> <script>spaghet.innerHTML (new URL(location).searchParam…