[笔记]动态规划与01背包问题
此笔记为个人学习记录,欢迎大佬指出误区,如有和你的认知矛盾之处,以你为准
关于动态规划
基本思想:避免重复计算
适用问题特征:重复子问题
如何实现:将原问题拆分为若干个更小的问题,通过dp数组存储子问题的结果,
(想象一个金字塔,先把最底层的盖完后,第二层就能在最底层的基础上再盖,以此类推),
在某个较大子问题包含已经求解过的子问题的时候,直接从dp数组中取得该结果,得出结果后再次存入dp数组,以避免该子问题的重复计算,
以此类推,当某个更大的子问题包含这个较大子问题时,同样可以直接从dp数组中再次取得结果,直到问题解决。
思考过程
显然动态规划的灵魂所在就是dp数组(Dynamic Programming)
所以首先得明确dp数组的下标(还有要使用一维还是更多维的数组)和其对应的子问题的含义
然后确定递推公式:即上述中子问题,较大子问题和更大的子问题之间是如何转换的(这一步一般是最难也是最关键的)
之后将dp数组初始化,确定遍历顺序,找几个例子检验一下即可
01背包问题
概述
有N件物品和一个容量为W的背包。
每第i件物品的重量为weight[i],价值为value[i]。
每件物品仅有一件,可选择装与不装。
求解选择装入哪些物品时得到的价值最大。
思考过程
建立dp数组://存放子问题的结果
对dp[i][j]:
i:[0…i]号备选物品
注意这里是从0号到i号之间的所有物品
j:背包的容量上限
时刻注意dp[i][j]数组仅存放了一个数字,这个数字对应着条件为i和j时的最优解
递推公式推导://建立i与i-1之间的关系
首先固定背包容量为j,对每一个第i件物品有两种选择:
1>不放入这个第[i]件物品:
此时有 dp[i][j]=dp[i-1][j] //相当于不存在这一件物品(这一件物品不影响问题的最优解)
所以结果为0~i-1(没有第i件物品)时的最优解
2>放入这个第i件物品时:
有dp[i][j]=+value[i]+dp[i-1][j-weight(i)] //优先处理这一件物品,获得价值value[i],同时背包容量减少这件物品的重量即[j-weight(i)]
此时背包大概率还是能装下一点别的东西的,这点剩下的容量能装下的价值就是dp[i-1][j-weight(i)](因为第i号物品已经在包里了,所以备选物品从0~i-1里选)
那么到底是装还是不装呢,只需要对上面两种情况带来的价值进行比较即可,于是得到递推公式
dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);
dp数组初始化
显然备选物品数量和背包容量不应该为负值,但是由递推公式可以预料到,i=0时,i-1就为负值,所以在i=0时,不应依照递推公式,而是应当自己手动对其进行赋值,以便后续的问题依次进行解决
对dp[0][j]:此时备选物品仅有第0号(也就是第一件,这里标为0只是为了对应数组规则)物品,此时对与容量为j的背包有两种可能:
当背包容量装不下第0号物品时,即j<weight(0)时,dp[0][j]=0;
当背包能装下第0号物品时,即j>=weight(0)时,dp[0][j]=value(0);