0/1背包

0/1背包

背包问题是DP最经典的类型之一,而0/1背包是最经典最基础的背包问题。

一个背包体积为 v v v,现有 n n n种物品,第 i i i个物品对应体积为 c i c_i ci,价值为 w i w_i wi,每件物品最多可放1次,求解怎样放置能使背包总价值最大?

由于每件物品只有选(0)与不选(1)两种情况,故称为0/1背包问题。

分析:闫氏DP分析法

闫氏DP分析法
  • 状态表示

    • 集合:定义数组 d p [ i ] [ j ] dp[i][j] dp[i][j],表示当前选取方案的价值。第 i i i行表示只考虑前 i i i个物品的放置情况, j j j表示当前选取体积不超过 j j j的方案集合。 i n i t ( d p [ 0 ] [ i ] , d p [ j ] [ 0 ] ) = 0 init(dp[0][i],dp[j][0])=0 init(dp[0][i],dp[j][0])=0
    • 属性: M a x Max Max
  • 状态计算

    • d p [ i ] [ j ] dp[i][j] dp[i][j]:对于第 i i i个物品:
      • 选第 i i i个物品: d p [ i ] [ j ] = d p [ i − 1 ] [ j − c [ i ] ] + w [ i ] dp[i][j]=dp[i-1][j-c[i]]+w[i] dp[i][j]=dp[i1][jc[i]]+w[i],继承自前 i − 1 i-1 i1个物品的价值,体积减少 c [ i ] c[i] c[i],价值加 w [ i ] w[i] w[i]
      • 不选第 i i i个物品:第 i i i个物品 c [ i ] > j c[i]>j c[i]>j,无法装入背包;或不选该物品。 d p [ i ] [ j ] = d p [ i − 1 ] [ j ] dp[i][j]=dp[i-1][j] dp[i][j]=dp[i1][j],继承自前 i − 1 i-1 i1个物品的价值,体积和价值不变
  • 状态转移方程式: d p [ i ] [ j ] = m a x ( d p [ i − 1 ] [ j ] , d p [ i − 1 ] [ j − c [ i ] ] + w [ i ] ) dp[i][j]=max(dp[i-1][j],dp[i-1][j-c[i]]+w[i]) dp[i][j]=max(dp[i1][j],dp[i1][jc[i]]+w[i])

void init(){
    for(int i=0;i<=n;i++) dp[i][0]=0;
    for(int i=0;i<=v;i++) dp[0][j]=0;
}
void dp(){
    for(int i=1;i<=n;i++)
        for(int j=1;j<=v;j++)
            if(c[i]<=j) dp[i][j]=max(dp[i-1][j],dp[i-1][j-c[i]]+w[i]);
    		else dp[i][j]=dp[i-1][j];
}

时间复杂度O( n v nv nv),空间复杂度O( n v nv nv)

DP表

image-20240714135742848

滚动数组

DP问题的空间复杂度一般很高,可采用滚动数组方式对空间复杂度进行优化。

滚动数组原理是基于DP的无后效性,第 i i i行只与 i − 1 i-1 i1行有关,至于 i − 1 i-1 i1行之前的数据第 i i i行无需关注,因此在DP过程中实际上只有两行在进行工作,故可极大程度优化空间复杂度。

注意,滚动数组使中间信息丢失,若需要输出背包具体方案,则不能采用滚动数组。

交替滚动

思路:定义 d p [ 2 ] [ v ] dp[2][v] dp[2][v],当前工作指针 w o r k work work和上次工作指针 o l d old old,使用 d p [ w o r k ] [ v ] dp[work][v] dp[work][v] d p [ o l d ] [ v ] dp[old][v] dp[old][v]进行交替滚动,每次滚动后交换工作指针即可,思路简单

int dp[2][v];
void dp(){
    int work=0,old=1;
    for(int i=1;i<=n;i++){
        swap(work,old);//交换工作指针而非交换数组元素
        for(int j=1;j<=v;j++)
            if(c[i]<=j) dp[work][j]=max(dp[old][j],dp[old][j-c[i]]+w[i]);
        	else dp[work][j]=dp[old][j];
    }
}

自我滚动

思路:由状态转移方程式可知,当前元素只继承自上一行正上方( d p [ i − 1 ] [ j ] dp[i-1][j] dp[i1][j])或上一行左上方( d p [ i − 1 ] [ j − 1 ] dp[i-1][j-1] dp[i1][j1]),因此逆序遍历背包容量进行更新,可将数组压至一维。

在这里插入图片描述

int dp[v];
void dp(){
    for(int i=1;i<=n;i++){
        for(int j=v;j>=c[i];j--)//装不下的不用管
            dp[j]=max(dp[j],dp[j-c[i]]+w[i]);
    }
}

输出具体方案

思路:定义标记数组,从 d p dp dp终点开始步步向上回溯,根据0/1背包状态转移方程式 p [ i ] [ j ] = m a x ( d p [ i − 1 ] [ j ] , d p [ i − 1 ] [ j − c [ i ] ] + w [ i ] ) p[i][j]=max(dp[i-1][j],dp[i-1][j-c[i]]+w[i]) p[i][j]=max(dp[i1][j],dp[i1][jc[i]]+w[i])可知,判断 d p [ i ] [ j ] dp[i][j] dp[i][j] d p [ i − 1 ] [ j ] dp[i-1][j] dp[i1][j] d p [ i − 1 ] [ j − c [ i ] ] + w [ i ] dp[i-1][j-c[i]]+w[i] dp[i1][jc[i]]+w[i]关系即可判断第 i i i个物品是否已装,最后输出标记数组。

注:求解具体方案仅适用于非滚动数组,因为滚动过程会将中间状态信息丢失。

extern int dp[MAX][MAX],i,j;//i,j:dp终点
bool f[MAX];
void print(){
    for(;i>=1;i--){
        if(j>=c[i]&&dp[i][j]==dp[i-1][j-c[i]+w[i]]){//说明第i个物品已选
            f[i]=1;
            j-=c[i];
        }
    }
    for(int k=1;k<=n;k++) if(f[k]) cout<<k<<' ';
}

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

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

相关文章

初识影刀:EXCEL根据部门筛选低值易耗品

第一次知道这个办公自动化的软件还是在招聘网站上&#xff0c;了解之后发现对于办公中重复性的工作还是挺有帮助的&#xff0c;特别是那些操作非EXCEL的重复性工作&#xff0c;当然用在EXCEL上更加方便&#xff0c;有些操作比写VBA便捷。 下面就是一个了解基本操作后&#xff…

如何追踪ping连接中的所有路由器的数量和IP

如何快速判断ping连接经过的路由器个数和IP&#xff1f; 方法一&#xff1a; ping命令会返回一个TTL&#xff0c;TTL&#xff08;Time To Live&#xff09;存活时间&#xff0c;一般初始值为64&#xff0c;每经过一个路由器就减一&#xff0c;当TTL为0时丢弃网络包&#xff0…

【深度学习】PyTorch深度学习笔记01-Overview

参考学习&#xff1a;B站视频【《PyTorch深度学习实践》完结合集】-刘二大人 ------------------------------------------------------------------------------------------------------- 1. 基于规则的深度学习 2. 经典的机器学习——手动提取一些简单的特征 3. 表示学习…

Linux问题解决

1、打开VMware Workstation&#xff0c;开启需要安装VMware Tools的虚拟机&#xff0c;在顶部选择菜单栏的虚拟机选项卡&#xff0c;点击“安装VMware Tools(T&#xff09;”。 或者有时在底部会弹出提示框安装tools&#xff0c;点击安装也可以。 2、进入ubuntu系统后&#xff…

《Linux系统编程篇》vim的使用 ——基础篇

引言 上节课我们讲了&#xff0c;如何将虚拟机的用户目录映射到自己windows的z盘&#xff0c;虽然这样之后我们可以用自己的编译器比如说Visual Studio Code&#xff0c;或者其他方式去操作里面的文件&#xff0c;但是这是可搭建的情况下&#xff0c;在一些特殊情况下&#xf…

【Linux】数据流重定向

数据流重定向&#xff08;redirect&#xff09;由字面上的意思来看&#xff0c;好像就是将【数据给它定向到其他地方去】的样子&#xff1f; 没错&#xff0c;数据流重定向就是将某个命令执行后应该要出现在屏幕上的数据&#xff0c;给它传输到其他的地方&#xff0c;例如文件或…

4G LTE 教程 物理通道结构

https://www.artizanetworks.com/resources/tutorials/phy_cha.html 下行物理信道&#xff1a; 物理下行链路共享信道 (PDSCH) 承载 DL-SCH 和 PCH。DL-SCH 包含实际用户数据。物理下行链路控制信道 (PDCCH) 通知UEPCH和DL-SCH的资源分配情况&#xff0c;以及DL-SCH相关的HARQ…

tongweb8 使用命令行对应用进行操作(by lqw)

文章目录 声明思路和概念新增应用更新应用启动应用停止应用删除应用 声明 本帖只是做一些简单的应用查看&#xff0c;新增&#xff0c;启动&#xff0c;停止&#xff0c;删除操作&#xff0c;仅供参考&#xff0c;详细内容建议参考TongwebV8.0 命令行工具参考&#xff0c;生产…

InjectFix 热更新解决方案

简介 今天来谈一谈&#xff0c;项目种的客户端热更新解决方案。InjectFix是腾讯xlua团队出品的一种用于Unity中C#代码热更新热修复的解决方案。支持Unity全系列&#xff0c;全平台。与xlua的思路类似&#xff0c;InjectFix解决的痛点主要在于Unity中C#代码写的逻辑在发包之后无…

Python爬虫:基础爬虫架构及爬取证券之星全站行情数据!

爬虫成长之路&#xff08;一&#xff09;里我们介绍了如何爬取证券之星网站上所有A股数据&#xff0c;主要涉及网页获取和页面解析的知识。爬虫成长之路&#xff08;二&#xff09;里我们介绍了如何获取代理IP并验证&#xff0c;涉及了多线程编程和数据存储的知识。此次我们将在…

深度学习LSTM之预测光伏发电

代码一&#xff1a;训练LSTM模型 代码逐段分析 import numpy as np import pandas as pd import tensorflow.keras as tk from tensorflow.keras import layers首先&#xff0c;导入了必要的库&#xff1a;numpy用于数值计算&#xff0c;pandas用于数据处理&#xff0c;tenso…

k8s record 20240710 监控

不是adaptor 是opetator 案例 监控有了&#xff0c;日志搜集呢&#xff1f; 一、kubelet 的小弟 kubelet — 负责维护容器的生命周期&#xff0c;节点和集群其他部分通信 cAdvisor 集成在 Kubernetes 的 kubelet 中&#xff0c;能够自动发现和监控集群中所有的容器。dockers…

尚硅谷Vue3入门到实战,最新版vue3+TypeScript前端开发教程

Vue3 编码规范 创建vue3工程 基于vite创建 快速上手 | Vue.js (vuejs.org) npm create vuelatest 在nodejs环境下运行进行创建 按提示进行创建 用vscode打开项目 安装依赖 源文件有src 内有main.ts App.vue 简单分析 编写src vue2语法在三中适用 vue2中的date metho…

java《ArrayList篇》--ArrayList全套知识点总结及其配套习题逐语句分析(附带全套源代码)

一、前言 来不及悼念字符串了&#xff0c;接下来登场的是集合&#xff0c;集合和数组的用法差不多&#xff0c;不同之处就在于存储的内容&#xff0c;数组是固定的长度的&#xff0c;集合的长度不固定。学习的过程中可以参照数组 今天已经是学习java的第八天了&#xff0c;接下…

vue3 vite+gojs 2.3.14 去除水印

引用vue2的做法&#xff1a;http://t.csdnimg.cn/Yrz8n 自定义vite插件&#xff0c;插件中apply 分两种模式&#xff0c;如果打包请选择build&#xff0c;记得强制刷新浏览器清缓存采能看到最新的gojs界面 export default function createGojsWaterMaker() {return {name:rem…

FPGA笔试

半加器和全加器的区别&#xff1a; 1、半加器不考虑输入的进位&#xff0c;称之为半加。 2、全加器反之&#xff0c;考虑进位。 SRAM/DRAM优缺点对比_sram和dram的主要区别及优缺点-CSDN博客 消除竞争冒险的方法 ①滤波电容&#xff1a;因为尖峰脉冲很窄&#xff0c;用很小的…

PyFluent入门之旅(5)后处理

接着PyFluent入门之旅&#xff08;4&#xff09;算例求解后我们已经完成了求解&#xff0c;并且保存了.dat的结果文件。 现在可以利用Fluent内置的后处理功能进行图像与数据曲线的输出。 1. 计算结果文件的读取 如果需要在计算完成后立即进行后处理&#xff0c;那么直接在求…

Nginx入门到精通六(高可用配置)

下面内容整理自bilibili-尚硅谷-Nginx青铜到王者视频教程 Nginx相关文章 Nginx入门到精通一&#xff08;基本概念介绍&#xff09;-CSDN博客 Nginx入门到精通二&#xff08;安装配置&#xff09;-CSDN博客 Nginx入门到精通三&#xff08;Nginx实例1&#xff1a;反向代理&a…

【Django+Vue3 线上教育平台项目实战】构建高效线上教育平台之首页模块

文章目录 前言一、导航功能实现a.效果图&#xff1a;b.后端代码c.前端代码 二、轮播图功能实现a.效果图b.后端代码c.前端代码 三、标签栏功能实现a.效果图b.后端代码c.前端代码 四、侧边栏功能实现1.整体效果图2.侧边栏功能实现a.效果图b.后端代码c.前端代码 3.侧边栏展示分类及…

springboot1——快速构建项目

需求 第一步&#xff1a;创建maven工程(非web项目) 第二步&#xff1a;导入起步依赖 点击&#xff1a; 下拉复制&#xff1a; 粘贴&#xff1a;&#xff01;&#xff01;这是springboot工程需要继承的父工程 下拉复制&#xff1a; 粘贴&#xff1a;&#xff01;&#xf…