目录
一、01背包
描述:给定n个重量为w1,w2,w3.……Wn,价值为v1,v2,v3...Vn的物品和容量为C的背包,求这个物品中一个最有价值的子集,使得在满足背包的容量的前提下,包内的总价值最大。
01-背包:每个物品只能使用0次或1次。
package algorithm;
/**
* @ClassName Bag01
* Description 01背包
* @Auther 青青子衿
* @Date 2019/5/10 17:17
*/
public class Bag01 {
public static int Bag(int[] w, int[] v, int C) {
int size = w.length;
if (size == 0) {
return 0;
}
int[][] dp = new int[size][C+1];
//初始化第一行
//仅考虑容量为C的背包放第0个物品的情况
for (int i = 0; i <= C;i++) {
dp[0][i] = w[0]<=i? v[0]:0;
}
//下面外层for循环是依次放第1个物品~第size-1个物品的情况
//内层for循环是依次存储背包容量为0~C情况下能最大放的物品价值
for (int i = 1; i < size; i++) {
for (int j = 0; j <= C; j++) {
//要先保存上一行的值,不然直接max比较的话,有些情况可能为0
dp[i][j] = dp[i-1][j]; //这个地方一定要注意!!!
if (w[i] <= j) { //前提是能放得下,才考虑是放还是不放
dp[i][j] = Math.max(dp[i][j] ,dp[i-1][j-w[i]]+v[i]);
}
}
}
//完全是为了打印-让结果更清晰
for (int i = 0; i < size; i++) {
for (int j = 1; j <= C; j++) {
System.out.print(dp[i][j]+" ");
}
System.out.println();
}
return dp[size-1][C];
}
public static void main(String[] args) {
int[] w = {2, 1, 3, 2};
int[] v = {12, 10, 20, 15};
System.out.println(Bag(w, v, 5));
}
}
运行结果(看得更详细一点儿):
dp[i][j] | 背包容量为1 | 背包容量为2 | 背包容量为3 | 背包容量为4 | 背包容量为5 |
第1个物品 | 0 | 12 | 12 | 12 | 12 |
第2个物品 | 10 | 12 | 22 | 22 | 22 |
第3个物品 | 10 | 12 | 22 | 30 | 32 |
第4个物品 | 10 | 15 | 25 | 30 | 37 |
最后输出结果:
37
二、完全背包
完全背包问题是决策时对于每个物品,可以选择多次,只要背包还能装得下!01背包是规定每个物品只能选择一次。
01背包在选第i个物品时,背包容量够用的情况下,有2种状态可选:放or不放,找出最大价值的选择。
完全背包在选第i种物品时,背包容积够用的情况下,有多种状态可选,放0个(即不选),放1个,放2个,放3个……上限是放到背包放不下为止!找出最大价值的选择。
k = j/w[i]算出最多可以放几个。j是当前背包剩余容量,w[i]是当前物品重量。
代码见下(根据01背包稍作修改即可使用):
public class CompleteBag {
public static int bag(int[] w, int[] v, int C) {
int length = w.length;
int[][] dp = new int[length][C+1];
for (int i = 0; i <= C; i++) {
//在背包容量允许的情况下,为了最大价值,放入i / w[0]个v[0]物品
dp[0][i] = i / w[0] * v[0]; //放第一行也很重要,这个地方要做修改,要注意!!!!
}
int max =0;
for (int i = 1; i < length; i++) {
for (int j = 0; j <= C; j++) {
for (int k = 0; k <= j / w[i]; k++) {
int temp = dp[i-1][j-k*w[i]]+k*v[i];
if(max<temp){//遍历选择放入k个物品可以得到的价值最大
max = temp;
}
}
dp[i][j] = max;
max =0;
}
}
//为了结果更清晰,打印数组信息
for (int i = 0; i < length; i++) {
for (int j = 1; j <= C; j++) {
System.out.print(dp[i][j]+" ");
}
System.out.println();
}
return dp[length-1][C];
}
public static void main(String[] args){
int[] w = {1,2,3,4,5,6,7,8};
int[] v = {1, 5, 8, 9, 10, 17, 17, 20};
System.out.println(bag(w,v,8));
}
}
运行结果:
1 2 3 4 5 6 7 8
1 5 6 10 11 15 16 20
1 5 8 10 13 16 18 21
1 5 8 10 13 16 18 21
1 5 8 10 13 16 18 21
1 5 8 10 13 17 18 22
1 5 8 10 13 17 18 22
1 5 8 10 13 17 18 22
22