简体   繁体   English

背包,但物品数量均匀

[英]Knapsack but even amount of items

So, it's basically the same problem as the 0/1 knapsack problem: n items, each having a weight w_i, and a value v_i, maximise the value of all items but keeping the total weight less than W. However, their is a slight twist: The amount of items in the knapsack need to be even . 因此,这基本上是与0/1背包问题相同的问题:n个项目(每个项目的权重为w_i和值为v_i)使所有项目的值最大化,但总权重小于W。但是,它们很小扭曲: 背包中的物品数量必须均匀 The result should then be the total value of all the items in the knapsack. 结果应为背包中所有物品的总价值。

I tried the following: I use two DP tables of size (n+1) x (W+1), DP_odd and DP_even. 我尝试了以下操作:我使用两个大小为(n + 1)x(W + 1)的DP表,DP_odd和DP_even。 I filled them according to: 我根据以下条件填充了它们:

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] )

The result (the total value) should then be in DP_even[n][W]. 结果(总值)应为DP_even [n] [W]。 However, the result is incorrect. 但是,结果不正确。 I just get two equal DP tables. 我只得到两个相等的DP表。

Here is the implementation: 这是实现:

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

However, the result should be 20. Because the total value 23 can't consist of an even amount of items. 但是,结果应为20。因为总值23不能由偶数个项目组成。 It took the the items weigths[2], weights[3] and weights[5], but that's not an even amount... It should have taken weights[3] and weights[5]. 它采用了weigths [2],weights [3]和weights [5]等项,但这不是一个偶数...应该采用weights [3]和weights [5]。

For everyone that wants to see, here are the DP tables: (the first column is values[i], the second column is weights[i]: 对于每个想看的人,这里是DP表:(第一列是values [i],第二列是weights [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

Backtracking gives the solution: weights[2], weighst[3] and weights[5] => total values 23. 回溯给出了解决方案:weights [2],weightst [3]和weights [5] =>总值23。

Even though the method seems like it could work, it still doesn't. 即使该方法似乎可行,但仍然无效。

Is there another way to solve this? 还有另一种解决方法吗?

You can get a value of 20 by taking the 15 and the 5, so the result should be 20. 取15和5可以得到20的值,因此结果应为20。

DP_odd[i][j] = 0 isn't right because 0 items is not odd. DP_odd[i][j] = 0不正确,因为0项不是奇数。 The way it is now is symmetrical with DP_even so the result will be the same. 现在它的方式与DP_even对称,因此结果将相同。

Instead, set DP_odd[0][0] to a negative number and check for these negative numbers in the other sums and don't allow them to be used. 而是将DP_odd[0][0]设置为负数,并在其他总和中检查这些负数,并禁止使用它们。

So something like: 所以像这样:

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]);
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM