主页 > 开源代码  > 

01背包问题


1、01背包

【模板】01背包_牛客题霸_牛客网 (nowcoder.com)

1、1可以不装满

背包问题本质上还是一个线性dp。对于物品还是从1选到n。

1、状态表示:

经验 + 题目要求:

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

但是如果像这样表示dp的话,我们其实是无法解决问题的。

因为,考虑是否选取当前物品的时候,我们必须要考虑到当前背包的剩余容量,并且如果放入当前物品之后,还需要用到前面的dp状态。

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

2、状态转移方程:

根据最后一步的状况,分情况讨论。

从1号物品,选择到i号物品。那么对于最后一个位置的i号物品,就是两种情况:选或不选

情况1:

不选i物品:那么尽管走到i,但是是从1 ~ i-1个物品中选取,并且此时j还是j。则dp[i][j] = dp[i-1][j]。

情况2:

选i物品:那么选上i物品后,就需要从1 ~ i-1物品中选取物品,但是此时不应该超过的体积 = j - w[i],w[i]代表i号物品的体积。那么此时dp[i][j] = v[i] + dp[i-1][j - w[i] ]。

但是对于选i物品,需要考虑当前j是否能够容纳i号物品,即判断是否有 j >= w[i]。

即综上:dp[i][j] = max { dp[i-1][j] , v[i] + dp[i-1][ j-w[i] ] }。

3、初始化:

同样,我们多一行一列,方便填表。

保证第一行第一列正确:

第一列:j = 0,背包容量为0,那么此时最大价值0,则第一列0。

第一行:i = 0,0个物品,则最大价值为0,第一行0。

4、填表顺序:

由状态转移方程可知:dp[i][j]受上方dp的状态影响,以及左上方dp状态的影响。

则从上往下填表即可。

5、返回值:

dp[n][V]。

1、2、必须装满

1、状态表示:

dp[i][j]表示:从前i个物品中选取,装满容量为j的背包,所有方法中,能挑选出的最大价值。

2、状态转移方程:

这里约定:如果无法从前i个物品中挑选,正好装满j容量背包的话,dp[i][j] = -1。

为什么不约定为0呢。

因为对于dp[0][0] = 0,表示没有物品挑选,但是也是装满了容量为0的背包,所以此时价值为0。这里就和dp[0][0]作出区分。

那么其实这里的状态转移方程仍然没变:

不选i:dp[i][j] = dp[i-1][j]。即无论dp[i-1][j]是否有挑选方法,都赋值给dp[i][j]。

选i:dp[i][j] = v[i] + dp[i-1][j - w[i] ]。但是这种情况必须判断两个东西:j - w[i] >= 0,并且dp[i-1][j - w[i] ]不等于-1。必须判断在j -w[i]的容量下,是否有挑选方法。不然,后面在max中,如果j -w[i]容量下没有挑选方法,但是仍然会取到v[i] + dp[i-1][j - w[i] ],因为v[i] + dp[i-1][j - w[i] ]肯定比-1大。

但是如果j -w[i]容量下没有挑选方法,那么整体也是没有挑选方法的。

dp[i][j] = max { dp[i-1][j] , v[i] + dp[i-1][ j-w[i] ] }。

3、初始化:

将dp[0][0] = 0。

第一行 为-1(因为没有物品,无法凑满体积为j的背包,j≠0)。

第一列 为0(不选物品,也是凑满了体积为0的背包)。

4、填表顺序不变。

5、返回值不变。

#include<iostream> using namespace std; const int N = 1010; i
标签:

01背包问题由讯客互联开源代码栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“01背包问题