public class Knapsack {
// 0/1背包算法,填表x,f,找最大价值
public static void knapSack(int c, int n, int x[], int w[], int v[], int f[][]){
// 填表f[][],第0行,第0列为0 ,即f[i][0] = f[0][j] = 0
for (int i=0; i<=n; i++)
f[i][0] = 0;
for (int j=0; j<=c; j++)
f[0][j] = 0;
// 填表f[][],其他位置 f[i][j] = 核心公式
// 表f 的意义是记录 背包容量从0到c 时的每个容量时的背包能有的最大价值
for (int i=1; i<=n; i++) { // 依次计算第i行,第0行已经填完,从 1 开始
for (int j=1; j<=c; j++){ // 依次计算第i行每个元素,第0列已经填完,从 1 开始
if (w[i] > j)// 如果 第i个物品的重量>背包当前容量 ,即第i个物品不可装
f[i][j] = f[i-1][j]; // 最大价值量不变
else // 如果 第i个物品可装入,比较一下是装入价值大,还是不装入价值大
f[i][j] = Math.max(f[i-1][j], v[i] + f[i-1][j-w[i]]);
/* 此处,我原来有个错误认识,可以装,可以不装,那肯定装了价值大啊,
原来的理解错在哪,原来的理解是基于装进背包的物品就不再拿出来了,那肯定是越装越多,但是
v[i] + f[i-1][j-w[i]] 的意思是 当前此物品的价值+(当前背包容量-此物品重量)时的最大物品价值
(此种情况下可能会造成原来装入的物品已经被拿出来了)
这个核心公式正是表达了 最优子结构性质:一个问题的最优解 包含了 子问题的最优解
*/
}
}
// 打印 f 表的值
System.out.println("表 f 的值:");
for (int i=0; i<=n; i++){
for (int j=0; j<=c; j++)
System.out.printf("%-4d" , f[i][j]);
System.out.println();
}
// 填表 x[i],计算总价值
int j = c;
for (int i=n; i>0; i--) {
if (f[i][j] > f[i-1][j]) { // 如果 第i个物品装入
x[i] = 1; // x[i] 置1
j -= w[i]; // 背包重量减去 w[i]
}
else // 如果 第i个物品不装入
x[i] = 0; // x[i] 置0,背包重量不变
}
// 打印 x 表的值 和 总价值
System.out.println("表 x 的值:");
for (int i=1; i<=n; i++)
System.out.print("x" + i + " = " + x[i] + "\t");
System.out.println();
System.out.printf("总价值为: %d", f[n][c]);
}
public static void main(String[] args) {
int c = 10; // 背包总重量为 10
int n = 5; // 总的物品数为 5
int x[] = new int[n+1]; // 是否装入 xi,即 xi = 1/0 (x[0]]位置不用)
int w[] = new int[]{0,2,2,6,5,4};// xi 的重量 (w[0]位置不用)
int v[] = new int[]{0,6,3,5,4,6};// xi 的价值 (v[0]位置不用)
int f[][] = new int[n+1][c+1]; // f[i][j] 前i个物品装入容量为j的包 所得到的最大价值
knapSack(c, n, x, w, v, f); // 调用0/1背包算法,填表x,f,找最大价值
}
}
01背包问题 动态规划 java(详细注释)
最新推荐文章于 2023-02-15 15:17:18 发布