欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 汽车 > 维修 > 动态规划---01背包问题理论总结

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

2024/10/24 16:33:28 来源:https://blog.csdn.net/m0_65096633/article/details/141867393  浏览:    关键词:动态规划---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]只能放入一个物品,即:背包里只放了一个物品。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com