0-1背包问题
N个物品(编号1,2,…,N),
重量 int w[N+1]
价值 int v[N+1]
背包容量 int S
- 具有重叠子问题
- 具有最优子结构
枚举(+剪枝)
每个物品选和不选,形成二叉树,再DFS
动态规划
递归写法:
dp(i,x)表示从1~i号物品中选,背包剩余容量为x,此状态下能达到的最大价值。
- 递推关系
dp(i,x) = max{ dp(i-1,x), dp(i-1,x-w[i])+v[i] } - 递归边界
i=0或x=0时,dp=0
x<0时,dp=-∞,表示不可能出现这种情况,在max中淘汰
#include <climits>
#include <algorithm>
const int NINF = INT_MIN;
int DP(int i, int x){
if(i==0 || x==0) return 0;
if(x<0) return NINF;
return std::max(DP(i-1,x), DP(i-1, x-w[i])+v[i]);
}
int main(){
int ans = DP(N, S);
}
递归中存在子问题的重复计算。实际计算量和枚举+剪枝相同,只不过递归是带着“剩余容量”从后往前枚举,后者是带着“已累计重量”从前往后枚举。
递推写法:
- 状态
dp[i][x]表示从1~i号物品中选,背包剩余容量为x,此状态下能达到的最大价值。 - 状态转移方程
d p [ i ] [ x ] = { m a x { d p [ i − 1 ] [ x ] , d p [ i − 1 ] [ x − w [ i ] ] + v [ i ] } if x ≥ w [ i ] d p [ i − 1 ]