1.0-1背包问题
问题描述:有N件物品和一个容量为V的背包。第i件物品的重量是w[i],价值是p[i]。求解将哪些物品装入背包可使这些物品的总重量不超过背包容量,且价值总和最大。
思路:每种物品仅有一件,可以选择放或不放。
F[i,v]表示前i件物品放入一个容量为v的背包可以获得的最大价值。状态转移方程为:
F[i,v]=max{F[i-1,v],F[i-1,v-w[i]]+p[i]}
将前i件物品放入容量为v的背包中,如果只考虑第i件物品的策略(放或者不放),那么就可以转化为一个只和前i-1件物品相关的问题。
- 如果不放第i件物品,问题变为前i-1件物品放入容量为v的背包中,价值为F[i-1,v];
- 如果放第i件物品,问题就转化为前i-1件物品放入容量为v-w[i]的背包中,价值为F[i-1,v-w[i]]+p[i];
问题:有编号分别为a,b,c,d,e的五件物品,它们的重量分别是2,2,6,5,4,它们的价值分别是6,3,5,4,6,每件物品数量只有一个,现在给你个承重为10的背包,如何让背包里装入的物品具有最大的价值总和?
思路1:建立二维数组 dp[][]。
ID | weight | price | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
a | 2 | 6 | 0 | 0 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 6 |
b | 2 | 3 | 0 | 0 | 6 | 6 | 9 | 9 | 9 | 9 | 9 | 9 | 9 |
c | 6 | 5 | 0 | 0 | 6 | 6 | 9 | 9 | 9 | 9 | 11 | 11 | 14 |
d | 5 | 4 | 0 | 0 | 6 | 6 | 9 | 9 | 9 | 10 | 11 | 13 | 14 |
e | 4 | 6 | 0 | 0 | 6 | 6 | 9 | 9 | 12 | 12 | 15 | 15 | 15 |
public class 背包问题 {
//w:重量 p:价值
public static int maxPrice(int V,int[] w,int[] p){
int[][] dp=new int[w.length][V+1];
for(int i=0;i<w.length;i++){
dp[i][0]=0;
}
for(int j=1;j<V+1;j++){
if(w[0]>j){
dp[0][j]=0;
}else{
dp[0][j]=p[0];
}
for(int i=1;i<w.length;i++){
if(w[i]>j){ //放不进去
dp[i][j]=dp[i-1][j];
}else{ //放进去
dp[i][j]=Math.max(dp[i-1][j], dp[i-1][j-w[i]]+p[i]);
}
}
}
return dp[w.length-1][V];
}
public static void main(String[] args){
int V=10;
int[] w={2,2,6,5,4};
int[] p={6,3,5,4,6};
int max=maxPrice(V, w, p);
System.out.println(max);
}
}
思路2:把二维数组变为一维数组。
2.完全背包问题
问题描述:有编号分别为a,b,c,d的四件物品,它们的重量分别是2,3,4,7,它们的价值分别是1,3,5,9,每件物品数量无限个,现在给你个承重为10的背包,如何让背包里装入的物品具有最大的价值总和?
思路:完全背包问题和01背包问题的区别在于每一件物品的数量都有无限个,而01背包每件物品数量只有一个。初始化时,当只考虑一件物品a时,F[1][j]=j/w[a]。递推公式计算时,F[i][y]=max{F[i-1][y],F[i][y-w[i]]+p[i]},注意这里当考虑放入一个物品i时应当考虑还可能继续放入i,因此是F[i][y]=max{F[i-1][y],F[i][y-w[i]]+p[i]},而不是F[i][y]=max{F[i-1][y],F[i-1][y-w[i]]+p[i]}。
public class 完全背包问题 {
public static int maxPrice(int V,int[] w,int[] p){
int max=0;
int[][] dp=new int[w.length][V+1];
for(int i=0;i<w.length;i++){
dp[i][0]=0;
}
for(int i=1;i<V+1;i++){
if(w[0]>V){ //放不下
dp[0][i]=0;
}else{
dp[0][i]=p[0];
}
for(int j=1;j<w.length;j++){
if(w[j]>i){
dp[j][i]=dp[j-1][i];
}else{
dp[j][i]=Math.max(dp[j-1][i], dp[j][i-w[j]]+p[j]);
}
}
}
for(int i=0;i<dp.length;i++){
for(int j=0;j<dp[0].length;j++){
System.out.print(dp[i][j]+" ");
}
System.out.println();
}
return dp[w.length-1][V];
}
public static void main(String[] args){
int V=10;
int[] w={2,3,4,7};
int[] p={1,3,5,9};
int res=maxPrice(V, w, p);
System.out.println(res);
}
}