每日OJ题_01背包①_牛客DP41 【模板】01背包(滚动数组优化)

目录

牛客DP41 【模板】01背包

问题一解析

问题二解析

解析代码

滚动数组优化代码


牛客DP41 【模板】01背包

【模板】01背包_牛客题霸_牛客网

#include <iostream>
using namespace std;

int main() {
    int a, b;
    while (cin >> a >> b) { // 注意 while 处理多个 case
        cout << a + b << endl;
    }
}
// 64 位输出请用 printf("%lld")

问题一解析

背包问题的状态表示非常经典,如果不知道怎么来的,可以先把它当成一个模板。

以某个位置为结尾,结合题目要求,定义一个状态表示:

dp[i][j] 表示:从前 i 个物品中挑选,总体积不超过 j ,所有的选法中,能挑选出来的最大价值。

状态转移方程:

线性 dp 状态转移方程分析方式,一般都是根据最后一步的状况,来分情况讨论:

  • 不选第 i 个物品:相当于就是去前 i - 1 个物品中挑选,并且总体积不超过 j 。此时 dp[i][j] = dp[i - 1][j] ;
  • 选择第 i 个物品:那么就只能去前 i - 1 个物品中,挑选总体积不超过 j - v[i] 的物品。此时 dp[i][j] = dp[i - 1][j - v[i]] + w[i] ; 。但是这种状态不一定存在,要判断 j >= v[i]。

综上,状态转移方程为: dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - v[i]] + w[i]) ;


初始化、填表顺序、返回值:

        多加一行,方便初始化,此时仅需将第一行初始化为 0 即可。因为什么也不选,也能满足体积不小于 j 的情况,此时的价值为 0 。填表顺序从左往右,最后返回dp[n][V] ; 


问题二解析

        第二问仅需微调一下 dp 过程的五步即可。 因为有可能凑不齐 j 体积的物品,因此把不合法的状态设置为 -1 。

以某个位置为结尾,结合题目要求,定义一个状态表示:

dp[i][j] 表示:从前 i 个物品中挑选,总体积正好等于 j ,所有的选法中,能挑选出来的最大价值。

状态转移方程:

线性 dp 状态转移方程分析方式,一般都是根据最后一步的状况,来分情况讨论:

  • 不选第 i 个物品:相当于就是去前 i - 1 个物品中挑选,并且总体积不超过 j 。此时 dp[i][j] = dp[i - 1][j] ;
  • 选择第 i 个物品:那么就只能去前 i - 1 个物品中,挑选总体积不超过 j - v[i] 的物品。此时 dp[i][j] = dp[i - 1][j - v[i]] + w[i] ; 。但是这种状态不一定存在,不仅要判断 j >= v[i] 还要判断 dp[i - 1][j - v[i]] 表示的情况是否存在,也就是 dp[i - 1][j - v[i]] != -1 。

综上,状态转移方程为: dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - v[i]] + w[i]) ;


初始化、填表顺序、返回值:

        多加一行,方便初始化,第一行第一个格子为 0 ,因为正好能凑齐体积为 0 的背包,但是第一行第一个格子后面都是 -1 ,因为没有物品,无法满足体积大于 0 的情况。第一列全为0。

填表顺序从左往右,最后返回dp[n][V] ; 


解析代码

#include <iostream>
#include <cstring>

using namespace std;

const int N = 1010; // OJ定义成全局方便,且空间不会轻易溢出
int n, V, v[N], w[N];
int dp[N][N];

int main()
{
    cin >> n >> V;
    for (int i = 1; i <= n; ++i) // 从1开始读数据
    {
        cin >> v[i] >> w[i];
    }
    for(int i = 1; i <= n; ++i)
    {
        for(int j = 0; j <= V; ++j)
        {
            dp[i][j] = dp[i - 1][j];
            if(j >= v[i])
                dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - v[i]] + w[i]);
        }
    }
    cout << dp[n][V] << endl;

    memset(dp, 0, sizeof(dp));
    for(int j = 1; j <= V; ++j)
    {
        dp[0][j] = -1;
    }
    for(int i = 1; i <= n; ++i)
    {
        for(int j = 0; j <= V; ++j)
        {
            dp[i][j] = dp[i - 1][j];
            if(j >= v[i] && dp[i - 1][j - v[i]] != -1)
                dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - v[i]] + w[i]);
        }
    }
    cout << (dp[n][V] == -1 ? 0 : dp[n][V]) << endl;

    return 0;
}


滚动数组优化代码

背包问题基本上都是利用滚动数组来做空间上的优化:(时间也有常数的优化)

  1. 利用滚动数组优化。
  2. 直接在原始代码上修改。

        第i行元素只依赖于第i-1行元素。理论上,只需要保持两行元素,所以只需两个数组交替滚动,就能完成dp数组的填充。因此空间复杂度从O(N^2) 变为O(N)。

        这里还可以直接用一个数组来进行优化:从前往后去更新数组,dp[j - v[ i ]]肯定不比dp[ j ]的值大,而改了前面,后面的更新就会用到前面更新的数据,而本来应该使用原二维数组 i - 1行的数据,也就是更新数据之前的,因此可以巧妙地从后往前遍历,这样就可以避免用到更新后的数据。

在01背包问题中,优化的结果为:

  1. 删掉所有的横坐标。
  2. 修改一下 j 的遍历顺序。

(滚动数组优化代码只需能在原代码上修改就行,不用考虑什么状态表示)

#include <iostream>
#include <cstring>

using namespace std;

const int N = 1010; // OJ定义成全局方便,且空间不会轻易溢出
int n, V, v[N], w[N];
// int dp[N][N];
int dp[N]; // 滚动数组优化,把所有dp表左边一维坐标删掉,修改遍历顺序

int main()
{
    cin >> n >> V;
    for (int i = 1; i <= n; ++i) // 从1开始读数据
    {
        cin >> v[i] >> w[i];
    }
    for(int i = 1; i <= n; ++i)
    {
        for(int j = V; j >= v[i]; --j) // 滚动数组优化
        {
            dp[j] = dp[j];
            dp[j] = max(dp[j], dp[j - v[i]] + w[i]);
        }
    }
    cout << dp[V] << endl;

    memset(dp, 0, sizeof(dp));
    for(int j = 1; j <= V; ++j)
    {
        dp[j] = -1;
    }
    for(int i = 1; i <= n; ++i)
    {
        for(int j = V; j >= v[i]; --j) // 滚动数组优化
        {
            if(dp[j - v[i]] != -1)
                dp[j] = max(dp[j], dp[j - v[i]] + w[i]);
        }
    }
    cout << (dp[V] == -1 ? 0 : dp[V]) << endl;

    return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

智慧污水井物联网远程监控案例

智慧污水井物联网远程监控案例 在当今数字化转型的浪潮中&#xff0c;智慧水务已成为城市基础设施建设的重要组成部分。其中&#xff0c;基于物联网技术的智慧污水井远程监控系统以其高效、精准、实时的特性&#xff0c;在提升污水处理效能、保障城市水环境安全、实现精细化管…

Jmeter安装与测试

一&#xff1a;JMeter简介&#xff1a; JMeter&#xff0c;一个100&#xff05;的纯Java桌面应用&#xff0c;由Apache组织的开放源代码项目&#xff0c;它是功能 和性能测试的工具。具有高可扩展性、支持Web(HTTP/HTTPS)、SOAP、FTP、JAVA 等多种协议的特点。 官方网站&#x…

利用虚拟机建ITtools

网上给的虚拟机多数都是VMX格式的封包&#xff0c;而我这次用的是ovf 我先把虚拟机在导出为ovf 生成了三个文件 去服务器上创建虚拟机&#xff0c;选择从OVF或OVA文件部署虚拟机&#xff0c;点下一页 给虚拟机起个名字 把相应的文件扡到里面去&#xff08;这里生成的四个文件中…

【软件使用-MEGA】基于NJ和ML方法构建进化树结果比较

文章目录 概要对比细节小结 概要 构建进化树有很多可选的算法&#xff0c;其中比较常用的NJ&#xff08;邻接法&#xff09;&#xff0c;也有基于似然法NL&#xff0c;如下图所示&#xff0c;构建进化树具体方法可以参考我之前写的【软件使用-MEGA】如何基于ML方法构建进化树 …

STM32笔记---CAN采样点设置和报错

STM32笔记---CAN采样点设置和报错 采样点设置再同步补偿宽度&#xff08;SJW&#xff09;设置 报错分析CAN中断使能寄存器CAN错误状态寄存器 采样点设置 以前配置CAN参数的BS1和BS2参数时认为总线波特率符合要求就可以了&#xff0c;其实同一个波特率可能对应多组参数设置的情…

LC 515.在每个树行中找最大值

515. 在每个树行中找最大值 给定一棵二叉树的根节点 root &#xff0c;请找出该二叉树中每一层的最大值。 示例1&#xff1a; 输入: root [1,3,2,5,3,null,9] 输出: [1,3,9] 示例2&#xff1a; 输入: root [1,2,3] 输出: [1,3] 提示&#xff1a; 二叉树的节点个数的范围是…

内存函数memcpy、mommove、memset、memcmp

1、memcpy函数 描述&#xff1a; C 库函数 void *memcpy(void *str1, const void *str2, size_t n) 从存储区 str2 复制 n 个字节到存储区 str1。 声明&#xff1a; void *memcpy(void *str1, const void *str2, size_t n)参数&#xff1a; str1 -- 指向用于存储复制内容的目标…

windows环境下实现ffmpeg本地视频进行rtsp推流

摘要&#xff1a;有时候服务端&#xff08;如linux&#xff09;或者边缘端&#xff08;jetson盒子&#xff09;需要接受摄像头的视频流输入&#xff0c;而摄像头的输入视频流一般为rtsp&#xff0c;测试时需要搭建摄像头环境&#xff0c;很不方便&#xff0c;因此需要对本地视频…

MySQL SQL基础入门-你想要的我尽可能覆盖全

什么是SQL&#xff1f; SQL&#xff08;Structured Query Language) ,结构化查询语言。SQL是一种专用语言&#xff0c;用户关系型数据库管理系统或者在关系流数据管理系统中进行流处理。 SQL怎么读&#xff1f;两种读法&#xff1a;一个字母一个字母读或者连起来读。 一个字母…

PostgreSQL入门到实战-第二十二弹

PostgreSQL入门到实战 PostgreSQL中表连接操作(六)官网地址PostgreSQL概述PostgreSQL中self-join命令理论PostgreSQL中self-join命令实战更新计划 PostgreSQL中表连接操作(六) 使用PostgreSQL自联接技术来比较同一表中的行 官网地址 声明: 由于操作系统, 版本更新等原因, 文…

springCloud项目打包 ,maven package或install打包报错

解决思路一&#xff1a; <build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>2.3.7.RELEASE</version></plugin><plugin>&…

新天龙八部3永恒经典之江山策仿官方_源码架设教程

本教程仅限学习使用&#xff0c;禁止商用&#xff0c;一切后果与本人无关&#xff0c;此声明具有法律效应&#xff01;&#xff01;&#xff01;&#xff01; 教程是本人亲自搭建成功的&#xff0c;绝对是完整可运行的&#xff0c;踩过的坑都给你们填上了 一. 效果演示 新天龙…

opencv 多线程读取和显示摄像头【python源码】

在Python中&#xff0c;使用OpenCV库实现多线程读取和显示摄像头通常涉及创建多个线程&#xff0c;每个线程负责从摄像头捕获视频帧并显示它们。但是&#xff0c;请注意&#xff0c;OpenCV本身并不直接支持多线程显示&#xff0c;因为cv2.imshow通常是在主线程中运行的。然而&a…

【C++ STL序列容器】deque 双端队列

文章目录 【 1. 基本原理 】【 1. deque 的创建 】1.1 创建一个空的 deque1.2 创建一个 n 个默认值的 deque1.3 创建一个 n 个指定值的 deque1.4 通过一个 deque 初始化另一个 deque1.5 通过基础容器来初始化 queue 容器适配器 【 3. deque 支持的成员函数 】 【 1. 基本原理 】…

什么是HW,企业如何进行HW保障?

文章目录 一、什么是HW二、HW行动具体采取了哪些攻防演练措施三、攻击方一般的攻击流程和方法四、企业HW保障方案1.建意识2.摸家底3.固城池4.配神器5.增值守 一、什么是HW 网络安全形势近年出现新变化&#xff0c;网络安全态势变得越来越复杂&#xff0c;黑客攻击入侵、勒索病…

【C语言】双向链表详解

文章目录 关于双向链表双向链表的初始化双向链表的打印双向链表方法调用 - 尾删为例双向链表的查找 - 指定位置之后插入为例双向链表结束 - 链表的销毁小结及整体代码实现 关于双向链表 首先链表有8种基本分法 其中在笔者之前文章种详细介绍的 单链表 是不带头单项不循环链表…

Leetcode算法训练日记 | day24

一、组合问题 1.题目 Leetcode&#xff1a;第 77 题 给定两个整数 n 和 k&#xff0c;返回范围 [1, n] 中所有可能的 k 个数的组合。 你可以按 任何顺序 返回答案。 示例 1&#xff1a; 输入&#xff1a;n 4, k 2 输出&#xff1a; [[2,4],[3,4],[2,3],[1,2],[1,3],[1,4…

别人起诉你你不服,到底是写上诉状还是反诉状?李秘书讲写作讲给你听!

别人起诉你你不服&#xff0c;到底是写上诉状还是反诉状&#xff1f;李秘书讲写作讲给你听&#xff01; 别人向法院告了你&#xff0c;你不服气&#xff0c;这时你可能想到要申辩或“报复”&#xff0c;但又不知是写上诉状呢还是写反诉状呢&#xff1f;#李秘书讲写作#这节就讲…

深度学习入门(2)

一。Matplotlib模块添加 Matplotlib是用于绘制图形的库&#xff0c;使用 Matplotlib 可以轻松地绘制图形和实现数据的可视化。 pip install matplotlib -i https://pypi.tuna.tsinghua.edu.cn/simple 二、绘制简单图形 import numpy as np import matplotlib.pyplot as plt #…

【电控笔记7】速度回路+系统延迟

2.3.1速度回路pi控制器设计 Tl:负载转矩