1、背包问题
- 背包问题:限定容量的背包,求放入物品总价值最大的方式
- 01背包:有N件物品和一个容量为V的背包,第i件物品消耗的容量为Ci,价值为Wi,求解放入哪些物品可以使得背包中总价值最大;
- 完全背包:有N种物品和一个容量为V的背包,每种物品都有无限件可用,第i件物品消耗的容量为Ci,价值为Wi,求解放入哪些物品可以使得背包中总价值最大;
- 多重背包:有N种物品和一个容量为V的背包,第i种物品最多有Mi件可用,每件物品消耗的容量为Ci,价值为Wi,求解入哪些物品可以使得背包中总价值最大。
2、Java代码
// 01背包问题
package Algorithm.KnapsackProblem;
/**
* @author bigyang
* @date 2020/11/02
*/
public class KnapsackProblem {
public static void main(String[] args) {
// 物品的重量
int[] w = {1, 4, 3};
// 物品的价值
int[] val = {1500, 3000, 2000};
// 背包的容量
int m = 4;
// 物品的个数
int n = val.length;
// 创建二维数组,记录背包中放入商品的情况
int[][] path = new int[n + 1][m + 1];
// 创建二维数组,v[i][j]表示前i个物品中能够装入容量为j的背包中的最大价值
int[][] v = new int[n + 1][m + 1];
// 初始化第一行和第一列
for (int i = 0; i < v.length; i++) {
v[i][0] = 0;
}
for (int j = 0; j < v[0].length; j++) {
v[0][j] = 0;
}
// 动态规划,第一行和第一列不处理
// 有i个物品可供选择:i=1说明只有吉他,i=2说明有吉他和音响,i=3说明有吉它、音响和电脑
for (int i = 1; i < v.length; i++) {
// j表示背包的容量
for (int j = 1; j < v[0].length; j++) {
// 如果第i个物品的重量比背包容量大,说明放不进去,此时 背包中的物品总价 等于 只有i-1个物品时的物品总价
if (w[i - 1] > j) {
v[i][j] = v[i - 1][j];
}
/*
如果放得进去,背包中的物品总价 = max(只有i-1个物品但占j空间时的物品总价,第i个物品价值+只有i-1个物品但占(j-第i个物品占空间)的价值)
v[i][j]:i个物品放入j空间后的物品总价
val[i-1]:第i个物品的价值
w[i-1]:第i个物品所占的空间
*/
else {
// 上次最优:只有i-1个物品但占j空间时的物品总价
int lastOptimal = v[i - 1][j];
// 可能地新的最优:第i个物品价值+只有i-1个物品但占(j空间-第i个空间)的价值
int newOptimal = val[i - 1] + v[i - 1][j - w[i - 1]];
if (lastOptimal < newOptimal) {
v[i][j] = newOptimal;
// 记录放入的路径
path[i][j] = 1;
} else {
v[i][j] = lastOptimal;
}
}
}
}
System.out.println("打印“填表法“填写的表:");
for (int i = 0; i < v.length; i++) {
for (int j = 0; j < v[i].length; j++) {
System.out.print(v[i][j] + " ");
}
System.out.println();
}
System.out.println();
// 输入要放入的商品
System.out.println("放入的顺序为:");
int i = path.length - 1;
int j = path[0].length - 1;
while (i > 0 && j > 0) {
if (path[i][j] == 1) {
System.out.printf("第%d个商品放入到背包\n", i);
j -= w[i - 1];
}
i--;
}
}
}
3、运行结果
打印“填表法“填写的表:
0 0 0 0 0
0 1500 1500 1500 1500
0 1500 1500 1500 3000
0 1500 1500 2000 3500
放入的顺序为:
第3个商品放入到背包
第1个商品放入到背包