背包问题学习

背包问题是常见的动态规划dp的问题

下面用到的符号:

  • 常用n表示物品数, m表示背包容积
  • f[i][j]表示i件物品, j的背包容量的最大价值
  • w[i]表示第i件物品的价值, v[i] 表示第i件物品的容量
  • f[0][0~m] = 0, 所以n可以从1开始遍历
  • 一般是有两层嵌套循环 第一层遍历物品, 第二层遍历背包容量, 第三层视情况, 若完全背包or多重背包 需要遍历决策 判断 k*v[i] <= j (背包容量)

0/1背包

下图是0/1背包的分析:
0/1背包问题的分析

题目 (0/1背包)

在这里插入图片描述

输入输出

输入输出

核心代码

for(int i = 1; i <= n; i++)for(int j = 0; j <= m; j++){ // 不难发现 f[i][] 都是依赖于 f[i-1][] 的f[i][j] = f[i-1][j];if(v[i]<=j) f[i][j] = max(f[i][j], f[i-1][j-v[i]]+w[i]);    
}

优化: 降维 二维 -> 一维

需要注意的是在遍历背包容量的时候, 需要逆序遍历背包容量, 因为物品只能取一个和不取两种状态, 而逆序能够保证这个。

完整代码如下:

#include<iostream>
#include<algorithm>using namespace std;
const int N = 1010;
int n, m;
int v[N], w[N]; // 物品体积 价值
int f[N]; int main(){scanf("%d%d",&n,&m);for(int i = 1; i<=n; i++) scanf("%d%d",&v[i],&w[i]);for(int i = 1; i<=n;i++){for(int j = m; j>=v[i]; j--){  // 每个物品只能使用一次 (逆序)f[j] = max(f[j], f[j-v[i]]+w[i]);}}printf("%d\n",f[m]);return 0;
}

完全背包

下图是完全背包的分析:

完全背包分析

题目(完全背包 物品可以无限拿, 只要背包容量还能放得下)
题目和输入/输出
题目输入和输出

朴素做法(三层循环)

#include<iostream>
#include<algorithm>using namespace std;const int N = 1010;int n, m;
int v[N], w[N];
int f[N][N];int main(){cin>>n>>m;for(int i = 1; i <= n; i++) scanf("%d%d",&v[i],&w[i]);for(int i = 1; i<=n; i++){ // 列举物品体积for(int j = 0; j<=m; j++){  // 列举背包for(int k = 0; k*v[i] <= j; k++)// 决策 (背包体积有限)f[i][j] = max(f[i][j], f[i-1][j-k*v[i]]+w[i]*k);}}cout<<f[n][m]<<endl;return 0;
}

优化:

(通过列举 f[i][j] 以及 f[i][j-v]两种情况, 发现有很多相同之处, 只相差个v) => 化简得

f[i]][j] = max(f[i-1][j], f[i-1][j-v]+w) 两种状态, 一个是取第i件物品, 另一个是不取第i件物品

 for(int i = 1; i <= n; i++){ // 列举物品for(int j = 0; j <= m; j++){ // 背包体积f[i][j] = f[i-1][j];if(j >= v[i]) f[i][j] = max(f[i][j], f[i][j-v[i]]+w[i]);}}

其实上述代码与0/1背包的代码有很多雷同的地方(都是两种状态, 要么取第i件, 要么不取), 只不过 0/1 背包是 f[i][j] = max(f[i][j], f[i-1][j-v[i]]+w[i]), 而完全背包是 f[i][j] = max(f[i][j], f[i][j-v[i]]+w[i]) (前一部分是不取第i件, 后面是取第i件的方案)
这个状态转移方程的含义可以这样理解:

  1. 不取第 i 件物品:这种情况下,背包的最大价值保持不变,即为 f[i][j]。这实际上是上一个状态的值,因为我们没有添加新的物品。
  2. 取第 i 件物品:如果我们决定把第 i 件物品放入背包中,那么背包的剩余容量变为 j-v[i]。因此,当前的总价值是放入这件物品之前的总价值 f[i][j-v[i]] 加上这件物品的价值 w[i]

对于上面代码的转化:

for(int i = 1; i<=n; i++){for(int j = v[i]; j <= m; j++){f[i][j] = max(f[i-1][j], f[i][j-v[i]]+w[i]);}
}

继续优化:

2维压缩成1维: 这里因为完全背包问题, 物品可以取无数次, 所以第二层循环循环遍历背包容量时, 顺序遍历

for(int i = 1; i<=n; i++){for(int j = v[i]; j <= m; j++){f[j] = max(f[j], f[j-v[i]]+w[i]);}
}
cout<<f[m]<<endl;

多重背包

与上面的背包问题不同的是每个物品数量有上限: 0~s[i]
题目:
题目输入输出

状态划分: 两种 -> 取第i件物品 / 不取第i件物品

朴素做法

状态方程:f[i][j] = max(f[i-1][j-k*v[i]]+w[i]*k, f[i][j]), k = 0, 1, 2... s[i]

初级版 多重背包

 #include<iostream>#include<algorithm>using namespace std;const int N = 110;int n, m;int s[N], v[N], w[N];int f[N][N]; // 1~N 个物品, 背包容量为N 所能达到的最大价值 (max)int main(){scanf("%d%d", &n,&m);for(int i = 1; i<=n; i++){ // 输入第i个物品的体积、价值和重量scanf("%d%d%d",&v[i],&w[i],&s[i]);}for(int i = 1; i <= n; i++){ // 物品for(int j = 0; j <= m; j++){ // 背包体积for(int k = 0; k <= s[i] && k*v[i] <= j; k++)f[i][j] = max(f[i-1][j], f[i][j-k*v[i]]+w[i]*k);}}printf("%d\n",f[n][m]);return 0;}

当数据量比较大的时候, 上面的代码会出现 TLE, 因此我们需要对上述代码进行优化
优化:

困难版 多重背包
我们可以尝试展开f, 尝试寻找规律

f[i][j] = max(f[i-1][j], f[i-1][j-v]+w,...,f[i-1][j-sv]+sw)

f[i][j-v] = max( f[i-1][j-v], f[i-1][j-2v]+w,...+f[i-1][j-sv]+(s-1)w, f[i-1][j-s+1]v+sw)

但是从上式找不到其中规律,所以下述使用二进制拆解第i个物品个数s[i] 去优化上述代码

2^n的方式进行拆解包-> 01背包问题 s->logs 组, 且每组只能选一次 (拆分)

 #include<iostream>#include<algorithm>using namespace std;const int N = 25000, M = 2010; // 物品数量N NlogS 1000*log2000, 背包体积 Mint n, m;int v[N], w[N]; // 物体体积, 价值int f[N]; // dp数组, 这里使用一维数组, 因为物品数量进行重组了/*多重背包的优化 (二进制对物品数量进行拆分)对物品进行拆分, 这样就少了一层循环(第三层k)*/int main(){cin>>n>>m;int cnt = 0;for(int i = 1; i <= n; i++){int a, b, s;cin>>a>>b>>s; // 输入 第i种物品的体积, 价值int k = 1;while(k <= s){ // 拆分次数 s[i]!cnt++;v[cnt] = a * k; // k个第i件物品体积 k个 第i件物品体积为aw[cnt] = b * k;  // 更新第i个物品的价值s -= k;k *= 2;}if(s > 0){ // 剩余的(s个物品)为一件cnt++;v[cnt] = a*s; w[cnt] = b*s;}}n = cnt; // 更新物品数量// 后继转为 0/1 背包问题, 每个物品 要么拿一次, 要么不拿for(int i = 1; i<=n; i++){for(int j = m; j >= v[i]; j--){f[j] = max(f[j], f[j-v[i]]+w[i]);}}cout<<f[m]<<endl;return 0;}

上述介绍了常见的三种背包问题的思路和基础代码模板以及相应的优化。希望各位大佬能够给予指导以及相应的意见, 后续时间也会取更新更多更丰富的算法内容, 谢谢大家的观看♥~

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

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

相关文章

什么是HTTPS加密协议?一篇文章带你走进HTTPS的世界

什么是HTTPS加密协议&#xff1f;一篇文章带你走进HTTPS的世界 大家好&#xff0c;我是微赚淘客系统的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01;今天我将带大家了解一个在互联网安全领域非常重要的概念——HTTPS加密协议。让我们一起走进…

模板错误:主模板的声明中不允许使用模板参数列表

没有主模板&#xff0c;所以编译报错 #include "killCmake.h"#include<string>using namespace std;template<typename T> class Point<char*, T> // 编译&#xff0c;报错error:主模板的声明中不允许使用模板参数列表 { public:Point(char* x, T…

PHP使用HTTP代码示例模板

PHP是一种广泛用于服务器端的编程语言&#xff0c;它提供了许多内置的函数和扩展&#xff0c;以便开发人员能够轻松地处理HTTP请求和响应。在PHP中&#xff0c;您可以使用以下代码示例模板来处理HTTP请求和生成HTTP响应。 php复制代码 <?php // 处理GET请求 if ($…

获取Github Copilot的Token

可以在线提取出Github Copilot插件的Token&#xff0c;这样的话就可以把Token拿来做别的用处了&#xff0c;比如共享给其他人 Github Copilot是一款由GitHub和OpenAI合作开发的人工智能编程助手。它利用机器学习和自然语言处理技术&#xff0c;能够根据用户的输入自动生成代码…

IDEA中配置Git

Git 在IDEA中使用Git1 在IDEA中配置Git2 在IDEA中使用Git2.1在IDEA中创建工程并将工程添加至Git2.2 将文件添加到暂存区2.3 提交文件2.4 将代码推送到远程仓库2.5 从远程仓库克隆工程到本地2.6 从远程拉取代码2.7 版本对比2.8 创建分支2.9 切换分支2.10 分支合并 3 使用IDEA进行…

数据结构与算法编程题49

假设不带权有向图采用邻接表G存储&#xff0c;设计实现以下功能的算法。 &#xff08;1&#xff09;求出图中每个顶点的出度。 &#xff08;2&#xff09;求出图中出度为0的顶点数。 &#xff08;3&#xff09;求出图中每个顶点的入度。 #include <iostream> using names…

私域最全养号攻略---微信

微信号的使用规则&#xff1a; 注册新微信、微信实名认证、主动添加好友、面对面建群、被动添加好友、进群限制、朋友圈限制、好友上限 微信权重加分规则&#xff1a; 基础信息是否完整、注册时间、微信使用行为、 微信权重扣分规则&#xff1a; 使用的环境是否正常、部分行为会…

基于python的微博情感分析与文本分类系统的设计与实现

完整下载&#xff1a;基于python的微博情感分析与文本分类系统的设计与实现.docx 基于python的微博情感分析与文本分类系统的设计与实现 "Design and Implementation of a Python-based Weibo Sentiment Analysis and Text Classification System" 目录 目录 2 摘要 …

centos 源码编译gcc10.2

前言 随着时代进步&#xff0c;很多编译需要c14等更高的编译环境。 安装包版本必选说明gcc10.2.0是gcc g cgmp6.2.0 是用于高精度整数运算的开源库mpfr4.1.0是用于高精度浮点数运算的开源库mpc1.2.1是用于高精度复数运算的开源库isl0.22是用于处理整数集合和多维多项式的开源…

Michael.W基于Foundry精读Openzeppelin第40期——ERC20Burnable.sol

Michael.W基于Foundry精读Openzeppelin第40期——ERC20Burnable.sol 0. 版本0.1 ERC20Burnable.sol 1. 目标合约2. 代码精读2.1 burn(uint256 amount)2.2 burnFrom(address account, uint256 amount) 0. 版本 [openzeppelin]&#xff1a;v4.8.3&#xff0c;[forge-std]&#x…

1.pipenv创建pyqt5虚拟环境

pipenv创建pyqt5虚拟环境 一、安装pipenv ​ cmd输入指令&#xff1a; pip install pipenv二、安装虚拟环境 cmd进入我要创建环境的目录下 我使用以下命令在当前目录下创建虚拟环境&#xff1a; pipenv --python 3.8创建一个基于Python 3.8的虚拟环境&#xff0c;并生成一个…

华为鸿蒙开发——开发及引用静态共享包(HAR)、应用配置文件

文章目录 简述一、创建HAR模块二、编译HAR模块三、应用配置文件&#xff08;Stage模型&#xff09;四、应用配置文件&#xff08;FA模型&#xff09;1、配置文件的内部结构&#xff08;1&#xff09;app&#xff08;2&#xff09;deviceConfig&#xff08;3&#xff09;module …

C - 语言->内存函数

目录 系列文章目录 前言 1. memcpy使⽤和模拟实现 1.2 memcpy函数的模拟实现: 2. memmove 使⽤和模拟实现 2.1memmove的模拟实现&#xff1a; 3. memset 函数的使⽤ 4. memcmp 函数的使⽤ 系列文章目录 ✅作者简介&#xff1a;大家好&#xff0c;我是橘橙黄又青&#xff…

Python-字典详解

字典&#xff1a;存储键值对的结构 键(key) 值&#xff08;value&#xff09; 根据key快速找到value&#xff08;一种映射关系&#xff09; 1、如何创建字典 1、a {} 2、b dict() 2、创建字典的同时设置初始值 a {id:1,name:zhangsan} 逗号分割&#xff0c; &#xff…

uniapp实战 —— 猜你喜欢(含滚动触底分页加载)

效果预览 组件封装 src\components\SUI_Guess.vue <script setup lang"ts"> import { ref, onMounted } from vue import type { GuessItem } from /types/index import { getGuessListAPI } from /apis/index import type { PageParams } from /types/global…

如何使用技术 SEO 优化 Pinterest 富图钉

Pinterest 可以影响搜索引擎排名&#xff0c;尤其是谷歌。不过&#xff0c;它的作用方式与其他搜索引擎优化因素不同。这就是 Google 将图钉放在 nofollow 列表中。但是&#xff0c;它们仍然可以作为搜索引擎优化的一个重要因素。 高质量的图钉具有高分辨率的图片、吸引人的内…

软件定制开发与标准化产品的比较及选择

随着信息技术的不断发展&#xff0c;软件已经成为企业运营中不可或缺的一部分。而在选择软件时&#xff0c;企业用户通常面临两个选择&#xff1a;软件定制开发和标准化产品。软件定制开发和标准化产品各有其优缺点&#xff0c;以下是对两者的比较和选择&#xff1a; 1.成本&a…

(汇川H5U-A8)Modbus Poll与AutoShop使用RS-485通讯

一、初步认识: AutoShop: Modbus Poll: 1、连接配置 ConnectionSerial PortRS-485转串口,所以是串口Serial SettingsCOM3当你插入串口后,会显示新的一个端口,就是这个端口通讯速率9600与PLC协议配置一致数据长度8与PLC协议配置一致奇偶校验位0与PLC协议配置一致停止位2…

用perl解决小朋友问的2的10000次方是多少的问题

2的10000次方是多少&#xff0c;用perl单行命令搞定&#xff0c; perl -Mbigint -le print 2**10000如果是安装了strawberry perl &#xff0c;在Windows控制台上输入&#xff0c;单行命令的单引号要换成双引号。 perl -Mbigint -le "print 2**10000"在git-bash中执…

医院有HIS系统,为什么还要开发预约挂号小程序?数据如何互通?

**医院HIS系统&#xff08;Hospital Information System&#xff09;能够协助医院提高管理效率、优化医疗服务&#xff0c;提升患者就诊体验&#xff0c;是医院管理的重要工具&#xff0c; 但HIS系统属于医院内部管理系统&#xff0c;患者挂号只能去到门诊线下人工挂号窗口&…