暴力递归
/**
* 暴力枚举
*
* @param i 输入规模
* @param capacity 背包容量
* @return 背包最大价值
*/
public int forceKnapsackSR(int i, int capacity) {
// 超重了
if (capacity < 0) {
return Integer.MIN_VALUE;
}
// 每一件商品都被选择完了
else if (i < 1) {
return 0;
}
int p1 = forceKnapsackSR(i - 1, capacity - c[i]) + v[i];
int p2 = forceKnapsackSR(i - 1, capacity);
// 选择第i件商品
// 该商品被算在其中
if (p1 > p2) {
plan[i] = true;
// 需要进行回溯
return forceKnapsackSR(i - 1, capacity - c[i]) + v[i];
} else {
plan[i] = false;
return forceKnapsackSR(i - 1, capacity);
}
}
/**
* 获得最优背包方案
*/
public void getPlan() {
for (int i = 1; i < plan.length; i++) {
// 如果被选中
if (plan[i]) {
System.out.print(" " + i + "件");
}
}
}
记忆数组优化
/**
* 使用记忆数组
*
* @param i 输入规模
* @param capacity 背包容量
* @return 背包最大价值
*/
public int memoryKnapsackSR(int i, int capacity) {
// 超重了
if (capacity < 0) {
return Integer.MIN_VALUE;
}
// 每一件商品都被选择完了
else if (i < 0) {
return 0;
}
if (memory[i][capacity] != 0) {
return memory[i][capacity];
}
int p1 = memoryKnapsackSR(i - 1, capacity - c[i]) + v[i];
int p2 = memoryKnapsackSR(i - 1, capacity);
// 选择第i件商品
// 该商品被算在其中
memory[i][capacity] = Math.max(p1, p2);
return memory[i][capacity];
}
动态规划
/**
* 动态规划
*
* @param n 输入规模
* @param capacity 背包容量
*/
public int dynamicKnapsackSR(int n, int capacity) {
// 枚举每一种商品
for (int i = 1; i <= n; i++) {
// 枚举商品的每一种可能重量从 1 ——> capacity
for (int j = 1; j <= capacity; j++) {
// 在容量不超出的情况下,选择下件商品使得背包的价值更大
if (c[i] <= j && v[i] + memory[i - 1][j - c[i]] > memory[i - 1][j]) {
memory[i][j] = v[i] + memory[i - 1][j - c[i]];
rec[i][j] = 1;
} else {
memory[i][j] = memory[i - 1][j];
rec[i][j] = 0;
}
}
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= capacity; j++) {
System.out.print(" " + memory[i][j] + " ");
}
System.out.println();
}
return memory[n][capacity];
}
/**
* 获得动态规划的最佳方案
*
* @param n 输入规模
* @param capacity 背包容量
*/
public void getBest(int n, int capacity) {
// 打印方案表
System.out.println("-----------------------------");
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= capacity; j++) {
System.out.print(rec[i][j] + " ");
}
System.out.println();
}
System.out.println("-----------------------------");
// 这里需要逆序
for (int i = n; i >= 0; i--) {
if (rec[i][capacity] == 1) {
System.out.print(" 第" + i + "件 ");
capacity = capacity - c[i];
}
}
}
优化空间的动态规划
/**
* 动态规划优化空间
* 只能够找出最大价值 无法获得最佳方案
* @param n 输入规模
* @param capacity 背包容量
*/
public int dynamicKnapsackSR1(int n, int capacity) {
// 枚举每一种商品
for (int i = 1; i <= n; i++) {
/*
* 枚举商品的每一种可能重量从 capacity ——> 1
* 这里必须从后往前否则会覆盖
* 算到如f[21] 的时候 f[14] 肯定被计算过了,被新的覆盖了(本来应该是0计算过后变成24)
* f[21] = Math.max(24 + f[24-10] == 24, f[21] == 0);
*/
for (int j = capacity; j >= 1; j--) {
// for (int j = 0; j <= capacity; j++) {
// 在容量不超出的情况下,选择下件商品使得背包的价值更大
if (c[i] <= j) {
f[j] = Math.max(v[i] + f[j - c[i]], f[j]);
}
}
// 输出每个商品的表
// System.out.println(Arrays.toString(f));
}
return f[capacity];
}
公共的问题初始化(测试用)
public class Knapsack {
// 保存每个商品的体积
private final int[] c;
// 保存每个商品的价值
private final int[] v;
// 保存最优方案
private final boolean[] plan;
// 二维记忆数组
private final int[][] memory;
private final int[] f;
// 动态记忆
private final int[][] rec;
/**
* 问题初始化
*
* @param count 输入规模
* @param capacity 背包容量
*/
public Knapsack(int count, int capacity) {
// 保存每个商品的体积 将第一位写作0方便对应真实物品下标
c = new int[]{0, 10, 3, 4, 5, 4};
// 保存每个商品的价值
v = new int[]{0, 24, 2, 9, 10, 9};
plan = new boolean[count + 1];
memory = new int[count + 1][capacity + 1];
f = new int[capacity + 1];
rec = new int[count + 1][capacity + 1];
}
}