背包但确切的重量

zut*_*tru 5 java algorithm knapsack-problem dynamic-programming

是否有一种算法可以确定具有精确重量 W 的背包?即它就像普通的 0/1 背包问题,其中 n 个物品的重量为 w_i,价值为 v_i。最大化所有物品的价值,但是背包中物品总重量需要正好有重量 W

我知道“正常”的 0/1 背包算法,但这也可以返回重量更轻但价值更高的背包。我想找到最高值但精确的 W 重量。

这是我的 0/1 背包实现:

public class KnapSackTest {
    public static void main(String[] args) {
        int[] w = new int[] {4, 1, 5, 8, 3, 9, 2};  //weights
        int[] v = new int[] {2, 12, 8, 9, 3, 4, 3}; //values

        int n = w.length;
        int W = 15; // W (max weight)

        int[][] DP = new int[n+1][W+1];

        for(int i = 1; i < n+1; i++) {
            for(int j = 0; j < W+1; j++) {
                if(i == 0 || j == 0) {
                    DP[i][j] = 0;
                } else if (j - w[i-1] >= 0) {
                    DP[i][j] = Math.max(DP[i-1][j], DP[i-1][j - w[i-1]] + v[i-1]);
                } else {
                    DP[i][j] = DP[i-1][j];
                }
            }
        }
        System.out.println("Result: " + DP[n][W]);
    }
}
Run Code Online (Sandbox Code Playgroud)

这给了我:

Result: 29
Run Code Online (Sandbox Code Playgroud)

(请问我的问题中是否有任何不清楚的地方!)

Mic*_*Rus 5

实际上,正如 @Shinchan 在评论中发现的那样,所接受的答案是错误的。

通过仅更改初始dp状态而不更改算法本身,您可以获得精确重量的背包。

初始化,而不是:

            if(i == 0 || j == 0) {
                DP[i][j] = 0;
            }
Run Code Online (Sandbox Code Playgroud)

应该:

            if (j == 0) {
                DP[i][j] = 0;
            } else if (i == 0 && j > 0) { // obviously `&& j > 0` is not needed, but for clarity
                DP[i][j] = -inf;
            }
Run Code Online (Sandbox Code Playgroud)

其余的与你的问题保持一致。


ami*_*mit 2

只需简单地设置DP[i][j] = -infinity最后一个else子句就可以了。

其背后的想法是稍微改变一下递归公式定义来计算:

  • 找到权j达到 item 的最大值i

现在,归纳假设将发生变化,正确性证明将与普通背包非常相似,但有以下修改:

DP[i][j-weight[i]] 现在是可以用 精确构造的最大值j-weight[i],并且您可以采用 item i,给出值DP[i][j-weight[i]],或者不采用它,给出值DP[i-1][j]- 这是当准确使用j第一i-1件物品的重量。

请注意,如果由于某种原因您无法构造DP[i][j],您将永远不会使用它,因为在查找 MAX 时,值 -infinity 将始终被丢弃。