01背包
01背包
给定 n 件物品,物品的重量为 w[i],物品的价值为 c[i]。现挑选物品放入背包中,假定背包能承受的最大重量为 V,问应该如何选择装入背包中的物品,使得装入背包中物品的总价值最大?
搜索算法
状态i表示考虑第i件物品,v表示当前背包重量,C表示当前最大价值。
dfs(i,v,C)
调用方式dfs(1,V,0)
时间复杂度O(2n)
void dfs(int i,int v,int C) { if (i==n+1) { if (C>ans) ans=C; } else { dfs(i+1,v,C); if (v>=w[i]) dfs(i+1,v-w[i],C+c[i]); } }
动态规划
特点是:每种物品仅有一个,可以选择放或不放。
dp[i][v]表示背包承重v 放i件物品时的最大价值。则状态转移方程为:
dp[n][V]为本问题的解
解释
“将前i件物品放入容量为v的背包”这个子问题,若只考虑每i件物品的策略(放或不放),那么就可以转化为一个只牵扯前i-1件物品的问题。如果不放第i件物品,那么问题就转化为“前i-1件物品放入容量为v的背包中”,此时最大价值为dp[i-1][v];如果放第i件物品,那么问题就转化为“前i-1件物品放入容量为v-w[i]的背包中”,此时能获得的最大价值为dp[i-1][v-w[i]]+c[i],显然从这两个策略中选择最大的才是此时的最优,即dp[i][v]=max(dp[i-1][v],dp[i-1][v-w[i]]+c[i])
提高
如果求得选择了哪些物品。
从dp[n][V]开始,如果dp[n][V]==dp[n-1][V]则第n件物品没有被放入,继续从dp[n-1][V]开始考虑…否则第n件物品被放入,继续从dp[n-1][V-w[i]]开始考虑…。
如果内存优化问题
一维数组
分析两维数组的状态转换方程可知dp[i][v]只与dp[i-1][v]和dp[i-1][v-w[i]]有关,可以进行内存优化。
dp[v]表示重量不超过v的最大价值,则dp[v]=max(dp[v],dp[v-w[i]]+c[i]当v>=w[i]时,i表示物品的数量从1~n。
注意遍历的顺序为逆序,这样才能保证推dp[v]时dp[v-w[i]]保存的是状态dp[i-1][v-w[i]]的值。
练习题