完全背包问题
完全背包问题是01背包的进阶版本,主体思想和01背包一致
完全背包题目背景通常为在一定体积情况下对一系列物品在体积和价值之间做出最优选择决策,使得选择出来的物品价值最优,且对于每个物品选择次数不做限制,这是完全背包问题和01背包问题不一样的地方
-
解法1
因为每个物品不限制次数,所以可以直接增加一个维度k,用三重循环的方式处理,状态表示为 dp[i][j][k]
,其含义为,在前 i 个物品中,当体积为 j 的情况下,第 i 个物品选择 k 次的最优价值,
所以由此可得相关模板代码
for(int i = 1; i <= n; i ++ )
for(int j = 0; j <= m; j ++ ){
dp[i][j]=dp[i-1][j]//可以一个都不取
for(int k = 0; k * w[i] <= j; k ++ )
dp[i][j] = max(dp[i][j], dp[i - 1][j - k * w[i]] + k * v[i]);//求出每一个 dp[i][j]
}
但是这种解法时间复杂度太高了,所以有了新的解法
-
解法2
动态规划的优化一般都是对代码或者状态计算方程进行一个等价变形。在考虑动态规划问题的时候,一定要先把基本的形式写出来,然后再对它进行优化
看一下 dp[i][j]
和 dp[i][j - w]
的求解公式:
dp[i][j] = max(dp[i-1][j],dp[i-1][j-w]+v,dp[i-1][j-2w]+2v,dp[i-1][j-3w]+3v......)
dp[i][j-w]= max(dp[i-1][j-w]+v,dp[i-1][j-2w]+2v,dp[i-1][j-3w]+3v......)
由此可以推出,dp[i][j]
完全可以由 dp[i][j-w]
推出来,他们之间刚好形成了一种错位关系,
例如dp[i][j-2w]
计算方法就是 dp[i][j-2w]=max(dp[i-1][j-2w],dp[i][j-2w-w]+v)
,为什么这里是只加一个v呢,因为 dp[i][j-2w]
在计算得时候,已经加了2v了,或者严格来说,已经经过判定,取了最优解了,这里只需要加上当前判断的物品的值了
由此可得,全新递推公式 dp[i][j]=max(dp[i-1][j],dp[i][j-w]+v)
;
(!注!)为什么这里第二个比较对象是和 dp[i]
比较而不是 dp[i-1]
呢,因为你是从之前取的情况推出来的,比如取k=3的时候,也就是物品 i 取k个,你是用k=2的情况来递推,也就是物品 i 取2个,这是同一层级的,并没有使用上一次循环的情况来递推,可以通过解法1来理解,
可得模板代码
for(int i = 1; i <= n; i ++ )
{
for(int j = 0; j <= m; j ++ )
{
if(w[i] <= j)//当前物品体积小于当前容积,才能装进去,才能去在取和不取之间做选择
dp[i][j] =max(dp[i - 1][j], dp[i][j - w[i]] + v[i]);//这里为什么前面是从dp[i-1]去推,后面是从dp[i]推,因为这里又回到了取和不取的情况,不取,就是上一层来推,取就是同一层级去推
else
dp[i][j] = dp[i - 1][j];
}
}