0-1背包
有一个容量为N的背包,要用这个背包装下的物品价值最大,这些物品有两个属性,体积w和价值v。
定义一个二维数组dp[i] [j],表示前i件物品体积不超过j的最大价值,第i件物品的体积为w,价值为v,根据第i件物品是否添加到背包中,可以分两种情况进行讨论。
- 第i件物品没有添加到背包,总体积不超过j的前i件物品的最大价值就是总体积不超过j的前i-1件物品的总价值,dp[i] [j]=dp[i-1] [j]
- 第i件物品添加到背包中,dp[i] [j]=dp[i-1] [j-w]+v
第i件物品可以添加也可以不添加,取决于哪种情况下最大价值更大。因此状态转移方程为:
dp[i] [j]=max(dp[i-1] [j],dp[i-1] [j-w]+v)
代码:
public int knapsack(int W,int N,int []weights,int []values){
int [][]dp=new int[N+1][W+1];
for(int i=1;i<=N;i++){
int w=weights[i-1];
int v=values[i-1]; //第i个物品的体积和价值
for(int j=1;j<=W;j++){
if(j>=w)
dp[i][j]=Math.max(dp[i-1][j],dp[i-1][j-w]+v);
else
dp[i][j]=dp[i-1][j];
}
}
return dp[N][W];
}
空间优化
在程序实现时可以对0-1背包进行优化。观察状态转移方程就可以知道,前i件物品的状态仅与前i-1件物品的转态有关,因此可以将dp定义为一维数组,其中dp[j]既可以表示dp[i-1] [j],也可以表示dp[i] [j]。此时
dp[j]=max(dp[j],dp[j-w]+v)
代码:
public int knapsack(int W,int N,int[]weights,int[]values){
int []dp=new int[W+1];
for(int i=1;i<=N;i++){
int w=weights[i-1];
int v=values[i-1];
for(int j=W;j>=1;j--){
if(j>=w)
dp[j]=Math.max(dp[j],dp[j-w]+v);
}
}
return dp[W];
}