背包问题(Java)
自从七月开始参加各厂笔试以来,遇到过很多次背包问题,每次都做得不太好,故学习总结一下
背包问题总述
0-1背包
有N件物品和一个容量为V的背包,第i件物品消耗的容量为weight[i],价值为value[i],求解放入哪些物品可以使得背包中总价值最大。
注意:每件物品只有一件
多重背包
有N种物品和一个容量为V的背包,第i种物品最多有num[i]件可用,每件物品消耗的容量为weight[i],价值为value[i],求解入哪些物品可以使得背包中总价值最大。
注意:每件物品有其对应的件数
完全背包
有N种物品和一个容量为V的背包,每种物品都有无限件可用,第i件物品消耗的容量为weight[i],价值为value[i],求解放入哪些物品可以使得背包中总价值最大。
注意: 每件物品有无限件
1、0-1背包问题
遇到一个新的物品只需要考虑装还是不装,状态方程如下
dp[i][j]表示前i件物品能装入容量为j的背包中的物品价值总和的最大值
if(weight[i-1] > j)
dp[i][j] = dp[i-1][j];//如果装了第j件超出容量,则不装
else
dp[i][j] = Math.max(dp[i-1][j],dp[i-1][j-weight[i-1]]+value[i-1]);
具体代码如下:
/**
* 0-1背包问题
* @param V 背包容量
* @param N 物品种类
* @param weight 物品重量
* @param value 物品价值
* @return
*/
public static int ZeroOnePack(int V,int N,int[] weight,int[] value){
//初始化动态规划数组int
int[][] dp = new int[N+1][V+1];
//将dp[i][0]和dp[0][j]均置为0
for(int i=1;i<N+1;i++){
for(int j=1;j<V+1;j++){
//由于weight和value数组下标都是从0开始,注意第i个物品的重量为weight[i-1],价值为value[i-1]
if(weight[i-1] > j)//如果第i件物品的重量大于背包容量j,则不装入背包
dp[i][j] = dp[i-1][j];
else//判断
dp[i][j] = Math.max(dp[i-1][j],dp[i-1][j-weight[i-1]]+value[i-1]);
}
}
return dp[N][V];
}
2、多重背包问题
需要额外考虑物品的数量问题
/**
* 多重背包
*
* @param args
*/
public static int manyPack(int V,int N,int[] weight,int[] value,int[] num){
//初始化动态规划数组
int[][] dp = new int[N+1][V+1];
for(int i=1;i<N+1;i++){
for(int j=1;j<V+1;j++){
if(weight[i-1] > j)
dp[i][j] = dp[i-1][j];
else{
//考虑物品的件数限制
int maxV = Math.min(num[i-1],j/weight[i-1]);
for(int k=0;k<maxV+1;k++){
dp[i][j]=Math.max(dp[i-1][j],dp[i-1][j-k*weight[i-1]]+k*value[i-1]);
}
}
}
}
return dp[N][V];
}
3、完全背包问题
/**
* 完全背包
* 思路分析:
* 注意这里当考虑放入一个物品 i 时应当考虑还可能继续放入 i,
* 因此这里是dp[i][j-weight[i]]+value[i], 而不是dp[i-1][j-weight[i]]+value[i]。
* 放第i件物品。这里的处理和01背包有所不同,因为01背包的每个物品只能选择一个
* *因此选择放第i件物品就意味着必须转移到dp[i-1][v-w[i]]这个状态;但是完全背包
*问题不同,完全背包如果选择放第i件物品之后并不是转移到dp[i-1][v-w[i]]这个状态,
*而是转移到dp[i][v-w[i]],这是因为每种物品可以放任意件(注意有容量的限制,因此
*还是有限的),放了第i件物品后还可以继续放第i件物品,直到第二维的v-w[i]无法保
*持大于等于0为止。
* @param V
* @param N
* @param weight
* @param value
* @return
*/
public static int completePack(int V,int N,int[] weight,int[] value){
int[][] dp = new int[N+1][V+1];
for(int i=1;i<N+1;i++){
for(int j=1;j<V+1;j++){
if(weight[i-1] > j)
dp[i][j] = dp[i-1][j];
else
dp[i][j] = Math.max(dp[i-1][j],dp[i][j-weight[i-1]]+value[i-1]);
}
}
returndp[N][V];
}