/**
* Created on 2021/7/1
* 参考链接 https://www.cnblogs.com/kkbill/p/12081172.html
* @Author ZFH
*/
public class BagQuestion1 {
/**
* 物品编号 1 2 3 4
* 物品体积 2 3 4 5
* 物品价值 3 4 5 6
*/
static int[] weight = {0,2,3,4,5}; //物品体积
static int[] value = {0,3,4,5,6}; //物品价值
static int bagWeight = 8; //背包容量
//定义V(i,j):当前背包容量 j,前 i 个物品最佳组合对应的价值
static int[][] bagWeightTable = new int[5][9]; //动态规划表 第一个参数代表物品体积 第二个参数代表当前背包容量
static int[] item = new int[weight.length];//存放最优解
public static void main(String[] args) {
// i 从 1 开始,要和 i - 1 作比较
for (int i = 1; i <= weight.length - 1; i++) {
// j 代表 当前背包容量
for (int j = 1; j <= bagWeight ; j++) {
//当 当前背包容量不足以容纳第 i 件 物品时
if ( j < weight[i]){
//就等于没装
bagWeightTable[i][j] = bagWeightTable[i - 1][j];
}else {
//装了也不一定是最优解,选最大的
//这里不好理解
//第一次第一行一个物品放进去产生了最大价值
//第二次第二行的物品要看当前背包容量放不放得下,放进去和之前比较哪个价值更大
// bagWeightTable[i - 1][j] 代表同样背包容量下的价值
// 剩余空间的价值 + 当前商品的价值
// bagWeightTable[i - 1][j - weight[i]] + value[i] 代表存放进去之后的价值
bagWeightTable[i][j] = Math.max(bagWeightTable[i - 1][j],bagWeightTable[i - 1][j - weight[i]] + value[i]);
}
}
}
findBest(4,8);
//动态规划表的输出
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 9; j++) {
System.out.print(bagWeightTable[i][j] + " ");
}
System.out.println();
}
//最优解输出
for (int i = 0; i < 5; i++) //最优解输出
System.out.print(item[i] + " ");
}
//回溯 倒序
private static void findBest(int i , int j){
if ( i > 0 ){
//如果相等,说明没把当前的加进去
if (bagWeightTable[i][j] == bagWeightTable[i - 1][j]){
item[i] = 0;
//递归遍历当前容量之前的物品
findBest(i - 1,j);
//如果当前容量大于第i个物品的体积 且 价值等于把第i个物品加入进去之后的价值,说明当前是最优解
}else if ((j - weight[i]) >= 0 && (bagWeightTable[i][j] == (bagWeightTable[i - 1][j - weight[i]] + value[i]))){
item[i] = 1;
findBest(i - 1,j - weight[i]);
}
}
}
}