【问题标题】:Knapsack with min weight最小重量的背包
【发布时间】:2021-03-23 10:20:24
【问题描述】:

这种背包问题的变体需要最小重量。目标是最小化成本,同时至少实现最小重量。

例如,我们有 6 件商品,重量为 {1, 1, 1, 5, 13, 3},成本为 {1, 1, 1, 5, 10, 12}。 假设最小重量为 15。

最佳解决方案是项目{1, 2, 5},总重量为 15,成本为 12。

我应该如何尽可能高效地实现这个算法?贪婪的选择不起作用,我应该修改原来的动态规划解决方案来适应这个问题吗?如果有,怎么做?

如果重要的话,我打算用 Java 来写。

【问题讨论】:

  • 为什么最优解不是物品{1, 2, 5}
  • 是的,非常感谢您指出这一点。我刚刚改了。

标签: java dynamic-programming knapsack-problem


【解决方案1】:

minCost[i] 表示容量为i 的背包可以容纳的最小值,costs[i] 表示第 i 项的成本,weights[i] 表示第 i 项的重量。然后,对于每个 i,minVal[i] 是从 1 到项目数的所有 j 的最小值。

那么,答案就是minCost数组中从最小权重到最大权重范围内的最小值。

final int[] weights = {1, 1, 1, 5, 13, 3}, costs = {1, 1, 1, 5, 10, 12};
final int minWeight = 15;
int maxWeight = 0;
for(final int weight: weights){
    maxWeight += weight;
}
final int[] minCost = new int[maxWeight + 1];
for(int i = 1; i <= maxWeight; i++){
    minCost[i] = Integer.MAX_VALUE;
}
for(int i = 0; i < weights.length; i++){
    for(int j = maxWeight; j >= weights[i]; j--){
        if(minCost[j - weights[i]] != Integer.MAX_VALUE){
            minCost[j] = Math.min(minCost[j], minCost[j - weights[i]] + costs[i]);
        }
    }
}
int answer = Integer.MAX_VALUE;
for(int i = minWeight; i <= maxWeight; i++){
    answer = Math.min(answer, minCost[i]);
}
System.out.println(answer);

Demo

【讨论】:

  • 非常感谢!能否简单解释一下这个算法的时间复杂度?
  • @Nimbus 是O(nm),其中n 是项目数,m 是最大重量。
【解决方案2】:

让我们定义函数 f(i,j),它给出从前 i+1 个项目 (0,1...i) 中选择项目的最小成本,其中这些项目的权重之和正好等于j,那么至少获得权重(minW=15)的最小成本将这样计算:

min(f(i,j)) where  i=0,1...n-1, j=minW,minW+1,.... maxW 
- n is the number of items 
- minW=15 in your case
- maxW is the maximum possible sum of all the given weights

你可以参考这段C++代码(非常类似于Java):

    const int maxW = 100;//the maximum weight, a problem constraint
    const int maxN = 100;//the maximum number of items, a problem constraint

    int n = 6; //input
    int w[maxN] = { 1, 1, 1, 5, 13, 3 };//the weights(should be read as an input)
    int c[maxN] = { 1, 1, 1, 5, 10, 12 };//the costs(should be read as an input)
    
    int f[maxN][maxW];
    for (int i = 0; i < maxN; i++)
        for (int j = 0; j < maxW; j++)
            f[i][j] = 1000000;//some big value

    int minW = 15;//the minimum weight(should be read as an input)
    
    int result = 1000000;
    
    f[0][w[0]] = c[0];//initialization
    for (int i = 1; i < n; i++) {
        for (int j = 0; j < maxW; j++) {
            
            f[i][j] = f[i - 1][j];//don't pick the i-th item

            if (j - w[i] >= 0) {//pick the i-th item if possible
                if (f[i][j] > f[i - 1][j - w[i]] + c[i])
                    f[i][j] = f[i - 1][j - w[i]] + c[i];
            }

            if (j >= minW and f[i][j] < result) {
                result = f[i][j];//store the minimum cost when the weight is >= minW
            }
        }
    }
    cout << result << endl;//print the result(12 in this case)

【讨论】:

    【解决方案3】:

    我们实际上可以通过稍微修改@Unmitigated的答案来实现O(n * targetMinWeight)而不是O(n * maximum weight)

    class Solution:
    
    
        def knapsack(self, n, costs, weights, target):
            MAX = float('inf')
            dp = [[0 for _ in range(n + 1)] for _ in range(target + 1)]
            for t in range(target + 1):
                dp[t][0] = MAX
            for i in range(n + 1):
                dp[0][i] = MAX
    
            for t in range(1, target + 1):
                for i in range(1, n + 1):
                    if t > weights[i - 1]:  # i - 1 because of the offset
                        dp[t][i] = min(dp[t][i - 1], dp[t - weights[i - 1]][i - 1] + costs[i - 1])
                    else:
                        dp[t][i] = min(dp[t][i - 1], costs[i - 1])
    
            return min(dp[target])
    
    sol = Solution()
    print(sol.knapsack(6, [1, 1, 1, 5, 10, 12], [1, 1, 1, 5, 13, 3], 15)) # returns 12
    
    
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-05-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多