背包九讲----01背包问题

article/2025/9/14 20:43:06

01背包问题是最基本的背包问题,它包含了背包问题中设计状态、方程的最基本思想,另外,别的类型的背包问题往往也可以转换成01背包问题求解。

dd大牛的文章中这样提到01背包问题:
题目
有N件物品和一个容量为V的背包。第i件物品的费用是c[i],价值是w[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。

基本思路
这是最基础的背包问题,特点是:每种物品仅有一件,可以选择放或不放。

用子问题定义状态:即f[i][v]表示前i件物品恰放入一个容量为v的背包可以获得的最大价值。则其状态转移方程便是:f[i][v]=max{f[i-1][v],f[i-1][v-c[i]]+w[i]}。

这个方程非常重要,基本上所有跟背包相关的问题的方程都是由它衍生出来的。所以有必要将它详细解释一下:“将前i件物品放入容量为v的背包中”这个子问题,若只考虑第i件物品的策略(放或不放),那么就可以转化为一个只牵扯前i-1件物品的问题。如果不放第i件物品,那么问题就转化为“前i-1件物品放入容量为v的背包中”;如果放第i件物品,那么问题就转化为“前i-1件物品放入剩下的容量为v-c[i]的背包中”,此时能获得的最大价值就是f [i-1][v-c[i]]再加上通过放入第i件物品获得的价值w[i]。

注意f[i][v]有意义当且仅当存在一个前i件物品的子集,其费用总和为v。所以按照这个方程递推完毕后,最终的答案并不一定是f[N] [V],而是f[N][0..V]的最大值。如果将状态的定义中的“恰”字去掉,在转移方程中就要再加入一项f[i][v-1],这样就可以保证f[N] [V]就是最后的答案。至于为什么这样就可以,由你自己来体会了。

优化空间复杂度
以上方法的时间和空间复杂度均为O(N*V),其中时间复杂度基本已经不能再优化了,但空间复杂度却可以优化到O(V)。

先考虑上面讲的基本思路如何实现,肯定是有一个主循环i=1..N,每次算出来二维数组f[i][0..V]的所有值。那么,如果只用一个数组f [0..V],能不能保证第i次循环结束后f[v]中表示的就是我们定义的状态f[i][v]呢?f[i][v]是由f[i-1][v]和f[i-1] [v-c[i]]两个子问题递推而来,能否保证在推f[i][v]时(也即在第i次主循环中推f[v]时)能够得到f[i-1][v]和f[i-1][v -c[i]]的值呢?事实上,这要求在每次主循环中我们以v=V..0的顺序推f[v],这样才能保证推f[v]时f[v-c[i]]保存的是状态f[i -1][v-c[i]]的值。伪代码如下:

for i=1..N
for v=V..0
f[v]=max{f[v],f[v-c[i]]+w[i]};

其中的f[v]=max{f[v],f[v-c[i]]}一句恰就相当于我们的转移方程f[i][v]=max{f[i-1][v],f[i- 1][v-c[i]]},因为现在的f[v-c[i]]就相当于原来的f[i-1][v-c[i]]。如果将v的循环顺序从上面的逆序改成顺序的话,那么则成了f[i][v]由f[i][v-c[i]]推知,与本题意不符,但它却是另一个重要的背包问题P02最简捷的解决方案,故学习只用一维数组解01背包问题是十分必要的。
 

 01背包问题 Acwing 02

有 N 件物品和一个容量是 V 的背包。每件物品只能使用一次。

第 i 件物品的体积是 vi,价值是 wi。

求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
输出最大价值。

输入格式

第一行两个整数,N,V,用空格隔开,分别表示物品数量和背包容积。

接下来有 N 行,每行两个整数 vi,wi,用空格隔开,分别表示第 i 件物品的体积和价值。

输出格式
输出一个整数,表示最大价值。

数据范围
0<N,V≤1000
0<vi,wi≤1000
输入样例
4 5
1 2
2 4
3 4
4 5
输出样例:
8

朴素版解法:二维空间解法
每件物品只能选一次,对于每种物品,我们有两种选择

1.不选第i个物品 -> f[i][j]=f[i-1][j]
等于选前i-1个物品,空间为j情况下的最优解
2.选第i个物品 -> f[i][j]=f[i-1][j-v[i]]+w[i]
如果选的话,前i-1个物品的体积最多为j-v[i]

在这两种情况中取较大值即可,即为当前情况的最优解。
 

#include<iostream>
#include<cstring>
#include<algorithm>using namespace std;const int N=1010;int n,m;
int f[N][N];  //f[i][j]表示前i个物品,背包容量是j的情况下的最大价值。 
int w[N];
int v[N];int main()
{cin>>n>>m;for(int i=1;i<=n;i++)cin>>v[i]>w[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-1][j-v[i]]+w[i]);} int res=0;for(int i=0;i<=m;i++)res=max(res,f[n][i]);cout<<res<<endl;return 0;
}

解法二:滚动数组优化:(只需要一个数组)

状态转移每次只与上一层有关,所以用一个一维数组就可以
转移方程:f[i]=max(f[i],f[i-v[i]]+w[i])

其实就相当于二维中的 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]) ,(这正好是完全背包一维的解法,每个物品可以选无限次)而从大到小算的话一定用的是上一层的状态

#include<iostream>
#include<cstring>
#include<algorithm>using namespace std;const int N=1010;int n,m;
int f[N]; 
int w[N];
int v[N];int main()
{cin>>n>>m;for(int i=1;i<=n;i++)cin>>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]);cout<<f[m]<<endl;return 0;
}

这时的f[i]表示空间<=i的最大价值,所以最后直接输出dp[m]即可,

若题目要求装满背包,即将物品恰装入一个容量为m的背包中,只需要将初始化条件改一改即可,----将dp数组初始化为负无穷,f[0]=0,即可确保状态一定是从0转移过来的。

 

 


http://chatgpt.dhexx.cn/article/kRoeMikG.shtml

相关文章

背包九讲(例题+代码)

背包九讲 文章目录 背包九讲01背包问题完全背包问题多重背包问题多重背包问题 I(二进制优化)多重背包问题 II(单调队列优化) 混合背包问题二维费用的背包问题分组背包问题有依赖的背包问题背包问题求方案数背包问题求具体方案 脉络图 01背包问题 题目&#xff1a; N件物品、容…

背包九讲.

背包九讲 背包问题完全背包问题多重背包问题 I多重背包问题 II多重背包问题 III混合背包问题二维费用的背包问题分组背包问题有依赖的背包问题背包问题求方案数背包问题求具体方案 背包问题 有 N 件物品和一个容量是 V 的背包。每件物品只能使用一次。 第 i 件物品的体积是 v…

背包九讲——全篇详细理解与代码实现

DD_engi 背包九讲的个人整理 写在前面 Last Modified:2021/9 博主重新审读了一下整篇文章&#xff0c;以我现在更进一步的理解更新了文章中的部分内容&#xff0c;有问题及疑惑可随时评论或私信&#xff0c;会及时回复&#xff01;&#xff01;! 更新进度&#xff1a;9/9:⑦有…

22 springboot依赖注入三种方式

1 基于构造函数的依赖注入 Spring 基于构造函数的依赖注入_w3cschoolJ虽然当前有关Spring Framework&#xff08;5.0.3&#xff09;的文档仅定义了两种主要的注入类型&#xff0c;但实际上有三种 public class UserServiceImpl implents UserService{private UserDao userDa…

Spring实现依赖注入的几种方式

Spring实现依赖注入的几种方式 1.基于有参构造实现 <bean id"user" class"com.ccu.twj"><constructor-arg name"name" value"张三"></constructor-arg><constructor-arg name"age" value"18&quo…

依赖注入三种方式

1.构造器函数注入 分为无参构造方法和有参构造方法两种方式&#xff0c;其中有参构造方法又包含三种方式。 有参构造的三种方式&#xff1a; 下标赋值参数类型赋值参数名赋值 案例&#xff1a; User.java public class User {private String name;private String mess;pub…

spring依赖注入的三种方式以及优缺点

spring依赖注入的三种方式以及优缺点 一.依赖注入的三种方式 1.通过构造器注入。&#xff08;spring4.3之后&#xff0c;推荐使用&#xff09; 2.通过setter注入。&#xff08;spring4.3之前&#xff0c;推荐使用&#xff09; 3通过filed注入。 二.三种方式的代码示例&…

依赖注入的三种方式和循环依赖的产生

什么是循环依赖 说白了就是对象之间的依赖关系成环 例如A->B,B->C,C->A&#xff0c;并不限于对象的多少&#xff0c;最终成环就是循环依赖&#xff0c;也因此循环依赖的发生可能是十分复杂的。&#xff0c;如果使用属性注入的话&#xff0c;开发过程中甚至很难察觉。…

[Spring] IoC的理解及三种依赖注入方式

[Spring] IoC的理解及三种依赖注入方式 Spring---IoC的理解及三种依赖注入方式IoC是什么意思依赖控制反转 Spring提供的依赖注入的三种方式setter注入&#xff08;属性注入&#xff09;构造器注入p命名空间注入&#xff08;工厂方法注入&#xff09; Autowired Spring—IoC的理…

Spring依赖注入的三种方式

目录 一、变量注入&#xff08;Field Injection&#xff09; 二、构造器注入&#xff08;Constructor Injection&#xff09; 三、setter方法注入 &#xff08;Setter Injection&#xff09; 四、使用场景 Spring的依赖注入&#xff0c;我们一般使用Autowired注解来完成&am…

依赖注入的三种方式

DI(依赖注入) 注入的三种方法&#xff1a;构造器方法注入&#xff0c;set注入&#xff0c;基于注解的注入&#xff08;接口注入&#xff09; 1&#xff1a;构造器方法注入 创建一个Address类&#xff1b; public class Address {private String address;public Address() {}pu…

Pubmedy的使用教程

使用方法如下&#xff1a; 使用前先配置Sci-Hub的地址&#xff0c;如果网址不失效&#xff0c;配置一次即可 选中文章的DOI&#xff0c;右击选择Sci-Hub Search即可自动跳转到文章对应的Sci-Hub界面

Pubmedy加载时显示程序包无效的解决方案

目前谷歌应用商城已经下架Pubmedy&#xff0c;本地安装又遇到程序包无效&#xff1a;“CRX_HEADER_INVALID”。 解决方案&#xff1a; 将PubMedy.crx重命名为PubMedy.rar或者PubMedy.zip解压到要安装的位置找到扩展程序选项&#xff0c;并启用开发者选项选择加载已解压的扩展程…

细胞实验文献检索——PubMed | MedChemExpress

今天我们就以小白的课题——自噬 (Autophagy) 为例&#xff0c;给大家展示一波。这个时候给大家隆重介绍我们的——PubMed。 PubMed 提到 PubMed&#xff0c;相信大家应该都不陌生&#xff0c;它是常用的国外数据库之一&#xff0c;也是小编查找文献最喜欢的工具。自成立以来…

免费获取论文全文的方法,SCI-HUB的使用教程

很多人不在学校期间需要看文献全文&#xff0c;很多人获取文章的方式或是在网上求助或是给原作者索要。在SCI—HUB出现后&#xff0c;这些麻烦都不需要。SCI—PUB上保存了超过了4700万篇科研文献。SCI—PUB的网址 使用方法&#xff1a; 方法一、打开网页将想要论文的URL地址&…

SCI-HUB丨最新文献网址

sci-hub&#xff1a;在我们获取文献与学术论文的道路上提供了极好的便利&#xff0c;可以从中得到免费的文献下载&#xff0c;但也因为这样遭到各大出版社&#xff1a;ai思为尔&#xff0c;施普林格&#xff0c;wiley等出版社的打击与封杀&#xff0c;使得Sci-Hub在域名上不得不…

pubmed显示服务器不稳定,PubMed天天用,可是你真的用对了吗?

你是用关键词在PubMed上找论文的吗&#xff1f;如果关键词好几个&#xff0c;由于单词间的空格键存在AND命令&#xff0c;导致明明要搜的是词组&#xff0c;搜索不是被放大就是缩小&#xff0c;很难检索到合适量且关联度高的文。例如&#xff0c;你想找和肠炎与肿瘤坏死因子相关…

pubmed文献批量化下载器

1.代码如下 import time import requests import pandas as pd import osdef getArticle(PMCID,NIHMSID,DOI,title,path):print(PMCID,NIHMSID,DOI,title,path)os.chdir(path)headers {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit…

PubMed插件:分区、影响因子和即时IF一目了然,还能秒下文献(亲测有效)

Pubmed作为生物医药研究者最常用的免费文摘数据库&#xff0c;素有检索江湖上的泰山北斗之称&#xff0c;用好Pubmed&#xff0c;其他一切pubmed镜像网站都是浮云。今天小编给大家介绍一款完全免费的无需登录的pubmed插件&#xff0c;他可以解决pubmed本身不显示杂志影响因子的…

干货分享|被PubMed收录的论文,在MEDLINE和SCIE能检索到吗?

PubMed PubMed是由美国国家医学图书馆&#xff08;National Library of Medicine&#xff0c;NLM&#xff09;的国家生物技术信息中心&#xff08;National Center for Biotechnology Information&#xff0c;NCBI&#xff09;开发研制的一个医学文献网络数据库。PubMed是当今…