动态规划---01背包问题理论总结

        题目:有n件物品和一个最多能背重量为w的背包。第i件物品的重量时weight[i],得到的价值是value[i]。每件物品只能用一次,求解将哪些物品装入背包里物品价值总和最大。

解法一:dp二维数组

1.dp数组的含义

        dp[i][j]表示将下标为(0,i)的物品任取,装入到最大容量为j的背包中,价值总和最大为多少。

2.dp数组的递推公式

        物品i不放入容量为j的背包中可以用dp[i-1][j]表示。

        物品i想要放入容量为j的背包中时,背包里至少要剩余容量weight[i]才可以,放入后背包中的价值总和为dp[i][j-weight[i]]+value[i]。

        所以dp[i][j]=max( dp[i-1] [j] , dp[i-1] [ j-weight[i] ]+value[i] )

3.dp数组初始化

        如果背包容量j为0,那么哪个物品都无法装入,所以dp[i][0]=0

        由第二步得出的递推公式可知,i是由i-1推导出来的,那么i=0时一定要初始化。dp[0][j]代表着把下标为0的物品装入到容量为j的背包中的最大价值。当j<weight[0]时,dp[0][j]=0,当j>=weight[0]时,dp[0][j]=value[0]。

        其他下标的初始值是什么都可以,因为后面都会被覆盖掉,经常会选择把它们都初始化为0

4.遍历顺序

        dp数组是一个二维数组,有两个遍历维度:物品,背包重量(容量)。

        结论是:先遍历物品也可以,先遍历背包重量也可以。正序遍历倒序遍历也都可以。一般都选择先正序遍历物品,再正序遍历背包重量。

        为什么都可以呢?观察递推公式,dp[i][j]是靠i-1那一行的数据推导出来的,先遍历物品后遍历背包重量的情况下计算i行时i-1行已经计算过了,先遍历背包重量后遍历物品的情况下dp[i-1] [j],dp[i-1] [ j-weight[i] ]都已经计算过了。

解法二:dp一维数组(滚动数组)

1.dp数组的含义

        二维数组把i-1层的数据拷贝到i层,递推公式就可以写成

                                dp[i][j]=max( dp[i] [j] , dp[i] [ j-weight[i] ]+value[i] )

        此时完全可以使用只保留j,使用一维数组表示该递推公式

                                dp[j]=max( dp[j] , dp [ j-weight[i] ]+value[i] )

dp[j]代表容量为j的背包,所背的物品价值最大可以是多少。

2.dp数组的递推公式

        dp[j]=max( dp[j] , dp [ j-weight[i] ]+value[i] )

3.dp数组初始化

        根据递归公式,dp数组在推导的时候一定是取价值最大的数。

        如果题目给的价值都是正整数,那么非0下标都初始化为0就可以了。

        如果题目给的价值有负数,则将非0下标初始化为负无穷。

        这样才能让dp数组在递归公式的过程中取得最大价值,而不是被初始值覆盖。

4.遍历顺序

        外层for循环遍历物品(正序),内层for循环遍历背包重量(倒序)。

        内层倒序保证了每个物品只放了一次,但如果正序遍历,那么一个物品会被重复多次加入。        

        举例说明:物品0的重量weight[0]=1,价值value[0]=15。

        如果正序遍历,dp[1]=dp[1-weight[0]]+value[0]=15,

                                dp[2]=dp[2-weight[0]]+value[0]=15+15=30。

                               物品0被加入了两次!

        如果倒序遍历,dp[2]=dp[2-weight[0]]+value[0]=0+15=15

                                 dp[1]=dp[1-weight[0]]+value[0]=0+15=15

        问:为什么二维dp不用倒序,一维dp就要倒序呢?

        答:二维dp中计算dp[i][j]使用的一直是i-1行的数据,没有受到i行数据的影响,而一维dp中计算i行的dp[j]初始化是i-1行数据,但在推导的过程中会逐渐覆盖掉i-1行的值,计算时会受到i行数据的干扰。

        问:为什么不能先遍历背包重量,再遍历物品呢?

        答:因为一维dp的写法,背包容量一定是要倒序遍历,如果遍历背包容量放在外层,那么每个dp[j]只能放入一个物品,即:背包里只放了一个物品。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值