0-1背包和完全背包问题的实现
public static void print(int[][] a) {<span style="white-space:pre"> </span>
for (int i = 0; i < a.length; i++) {
for (int j = 0; j < a[0].length; j++) {
System.out.print(a[i][j] + "\t");
}
System.out.println();
}
}
//完全的背包问题
public static void comlete(int[] v, int[] w, int c, int[][] m) {
int n = v.length - 1;
int jMax = Math.min(w[n] - 1, c);
//对于第一个装入的物品
for (int j = 0; j <= jMax; j++) {
m[n][j] = 0;
}
for (int j = w[n]; j <= c; j++) { //这点与0-1背包问题不同,根据当前背包的容量判断可以装入几个当前物品
m[n][j] = v[n] * (j / w[n]);
}
//后面装入的物品要根据前一个装入的价值判断是否装入
for (int i = n - 1; i >= 1; i--) {
jMax = Math.min(w[i] - 1, c);
for (int j = 0; j <= jMax; j++) {
m[i][j] = m[i + 1][j];
}
for (int j = w[i]; j <= c; j++) {
int f = j / w[i];
//这点跟0-1背包问题不同,但是原理一样,判断在当前背包容量的情况下装入多个当前物品,所以剩余容量以及价值都要乘以当前课以装<span style="white-space:pre"> </span>入数
m[i][j] = Math.max(m[i + 1][j], m[i + 1][j - w[i] * f] + v[i] * f);
}
}
print(m);
int[] x = new int[6];
tracebake1(m, w, v, c, x);
}
public static void knasp(int[] v, int[] w, int c, int[][] m) {
int n = v.length - 1;
int jMax = Math.min(w[n] - 1, c);
for (int j = 0; j <= jMax; j++) {
m[n][j] = 0;
}
for (int j = w[n]; j <= c; j++) {
m[n][j] = v[n];
}
for (int i = n-1; i >= 1; i--) {
jMax = Math.min(w[i] - 1, c);
for (int j = 0; j <= jMax; j++) {
m[i][j] = m[i + 1][j];
}
for (int j = w[i]; j <= c; j++) {
//m[i + 1][j - w[i]] + v[i]是背包如果装入当前物品的价值,j - w[i]为背包剩余的容量,根据剩余判断前一个物品在这个剩余容量时的价值即m[i + 1][j - w[i]]
//m[i + 1][j]表示前一个物品在当前容量为j的情况是的价值
m[i][j] = Math.max(m[i + 1][j], m[i + 1][j - w[i]] + v[i]);
}
}
print(m);
int[] x = new int[6];
tracebake(m, w, c, x);
}
private static void tracebake1(int[][] m, int[] w,int[] v, int c, int[] x) {
int n = w.length - 1;
for (int i = 1; i < n; i++) {
if (m[i][c] == m[i + 1][c]) { //当前位置与前一行当前位置的值相同代表没装入
x[i] = 0;
} else {
x[i] = m[i][c]/v[i];
c -= w[i]*m[i][c]/v[i];
}
}
x[n] = (m[n][c] > 0) ? 1 : 0;
for (int a : x) {
System.out.print(a + ",");
}
System.out.println();
}
/**
* 回溯求解对于各个物品是否装入
* @param m
* @param w
* @param c
* @param x
*/
private static void tracebake(int[][] m, int[] w, int c, int[] x) {
int n = w.length - 1;
for (int i = 1; i < n; i++) { //当前位置与前一行当前位置的值相同代表没装入
if (m[i][c] == m[i + 1][c]) {
x[i] = 0;
} else {
x[i] = 1;
c -= w[i];
}
}
x[n] = (m[n][c] > 0) ? 1 : 0;
for (int a : x) {
System.out.print(a + ",");
}
}
public static void main(String[] args) {
int[] v = new int[] { 0, 6, 3, 5, 4, 6 }; //物品的价值 创建6个只是为了统一下标
int[] w = new int[] { 0, 2, 2, 6, 5, 4 }; //物品的重量
int[][] m = new int[6][11]; //2维数组记录背包的价值状态
int c = 10; //背包容量
knasp(v, w, c, m);
// comlete(v, w, c, m);
}