因此,它与0/1背包问题基本上是同一个问题:n个项目,每个项目的权重为w_i,值为v_i,最大化所有项目的值,但保持总重量小于W.但是,他们的是一个轻微的扭曲:背包中的数量需要均匀。结果应该是背包中所有物品的总价值。
我尝试了以下内容: 我使用两个大小为(n + 1)x(W + 1),DP_odd和DP_even的DP表。我填写他们:
DP_even[i][j] = max( DP_even[i-1][j] || DP_odd[i-1][j - weights[i]] + values[i] )
DP_odd[i][j] = max( DP_odd[i-1][j] || DP_even[i-1][j - weights[i]] + values[i] )
结果(总值)应该在DP_even [n] [W]中。但是,结果不正确。我只得到两个相同的DP表。
以下是实施:
public class KnapSackEven {
public static void main(String[] args) {
int[] weights = new int[] {4, 3, 3, 5, 1, 2, 7, 12};
int[] values = new int[] {2, 1, 3, 15, 3, 5, 9, 4}};
int n = weights.length;
int W = 10;
int[][] DP_odd = new int[n+1][W+1];
int[][] DP_even = new int[n+1][W+1];
for(int i = 0; i < n+1; i++) {
for(int j = 0; j < W+1; j++) {
if(i == 0 || j == 0) {
DP_odd[i][j] = 0;
DP_even[i][j] = 0;
} else if(j - weights[i-1] >= 0) {
DP_even[i][j] = Math.max(DP_even[i-1][j], DP_odd[i-1][j - weights[i-1]] + values[i-1]);
DP_odd[i][j] = Math.max(DP_odd[i-1][j], DP_even[i-1][j - weights[i-1]] + values[i-1]);
} else {
DP_even[i][j] = DP_even[i-1][j];
DP_odd[i][j] = DP_odd[i-1][j];
}
}
}
System.out.println("Result: " + DP_even[n][W]);
}
}
Result: 23
但是,结果应为20.因为总值23不能包含偶数项目。它取了项目权重[2],权重[3]和权重[5],但这不是一个偶数......它应该采用权重[3]和权重[5]。
对于想要查看的每个人,这里是DP表:(第一列是值[i],第二列是权重[i]:
DP_even:
0 0 0 0 0 0 0 0 0 0 0 0 0
2 4 0 0 0 0 2 2 2 2 2 2 2
1 3 0 0 0 1 2 2 2 3 3 3 3
3 3 0 0 0 3 3 3 4 5 5 5 6
15 5 0 0 0 3 3 15 15 15 18 18 18
3 1 0 3 3 3 6 15 18 18 18 21 21
5 2 0 3 5 8 8 15 18 20 23 23 23
9 7 0 3 5 8 8 15 18 20 23 23 23
4 12 0 3 5 8 8 15 18 20 23 23 23
DP_odd:
0 0 0 0 0 0 0 0 0 0 0 0 0
2 4 0 0 0 0 2 2 2 2 2 2 2
1 3 0 0 0 1 2 2 2 3 3 3 3
3 3 0 0 0 3 3 3 4 5 5 5 6
15 5 0 0 0 3 3 15 15 15 18 18 18
3 1 0 3 3 3 6 15 18 18 18 21 21
5 2 0 3 5 8 8 15 18 20 23 23 23
9 7 0 3 5 8 8 15 18 20 23 23 23
4 12 0 3 5 8 8 15 18 20 23 23 23
回溯给出了解决方案:权重[2],权重[3]和权重[5] =&gt;总价值23。
即使该方法似乎可行,但它仍然没有。
还有另一种解决方法吗?
答案 0 :(得分:2)
你可以通过15和5得到20的值,所以结果应该是20。
DP_odd[i][j] = 0
不对,因为0项不奇怪。它现在的方式是DP_even
对称,所以结果是一样的。
相反,请将DP_odd[0][0]
设置为负数,并检查其他总和中的这些负数,并且不允许使用它们。
类似于:
public class KnapSackEven {
public static void main(String[] args) {
int[] weights = new int[] {4, 3, 3, 5, 1, 2, 7, 12};
int[] values = new int[] {2, 1, 3, 15, 3, 5, 9, 4};
int n = weights.length;
int W = 10;
int[][] DP_odd = new int[n+1][W+1];
int[][] DP_even = new int[n+1][W+1];
for(int i = 0; i < n+1; i++) {
for(int j = 0; j < W+1; j++) {
DP_even[i][j] = -1;
DP_odd[i][j] = -1;
if(i == 0 || j == 0) {
DP_odd[i][j] = -1;
DP_even[i][j] = 0;
} else if(j - weights[i-1] >= 0) {
if(DP_odd[i-1][j - weights[i-1]] >= 0) {
DP_even[i][j] = Math.max(DP_even[i-1][j], DP_odd[i-1][j - weights[i-1]] + values[i-1]);
}
if(DP_even[i-1][j - weights[i-1]] >= 0) {
DP_odd[i][j] = Math.max(DP_odd[i-1][j], DP_even[i-1][j - weights[i-1]] + values[i-1]);
}
}
if(i > 0) {
DP_odd[i][j] = Math.max(DP_odd[i][j], DP_odd[i-1][j]);
DP_even[i][j] = Math.max(DP_even[i][j], DP_even[i-1][j]);
}
}
}
System.out.println("Result: " + DP_even[n][W]);
}
}