【问题标题】:Knapsack with "at least X value" constraint具有“至少 X 值”约束的背包
【发布时间】:2016-06-30 10:23:46
【问题描述】:

您将如何解决这种背包的变体?

您有 n 个对象 (x1,...xn),每个对象的成本 ci 和值 vi (1

我正在尝试通过动态编程解决这个问题,我想到的是修改用于 K[n,c,X] 的常用表,其中 X 是我需要达到的最小值,但这似乎让我无处可去。有什么好主意吗?

【问题讨论】:

  • 背包的大小有上限吗??
  • 不,文中没有提到这方面的任何内容

标签: algorithm dynamic-programming knapsack-problem


【解决方案1】:

想出了一种方法来将其归结为最初的背包问题。

首先,假设您已在解决方案中包含所有项目。 您的成本是 Cost_Max,实现的价值是 Val_Max(应该 >= X 才能存在解决方案)。

现在,回忆一下最初的背包问题:给定一组重量为 W(i) 且值为 V(i) 的物品,找到重量限制 = w 的最大可实现值。

现在,我们将使用这个背包问题来查找所有要包含在我们的答案集中的项目

所以在你的问题中计算了 Cost_Max 和 Val_Max 之后,你要处理:

  • costs(ci's) 作为值(即 V(i)'s )
  • 值(vi's)作为权重(即 W(i)'s )
  • (Val_Max - X) 作为权重限制 w

这将为您提供在您的价值保持 >= X 的情况下可以消除的最大成本。

因此,如果从上述步骤中找到的成本是 Cost_Knapsack,那么您的答案是 Cost_Max - Cost_Knapsack。

【讨论】:

    【解决方案2】:

    这可以像我们解决背包问题一样完成,在每个索引处,我们尝试在背包内放入一个值或不放入一个值,这里背包的大小没有限制,因此我们可以放置任意数量的元素背包里面。

    那么我们只需要考虑那些满足size of the knapsack >= X条件的解决方案。

    背包的状态是DP[i][j],其中i是元素的索引,j是当前背包的大小,注意我们只需要考虑那些有j >= X的解决方案。

    以下是 c++ 中的递归动态编程解决方案:

    #include <iostream>
    #include <cstring>
    #define INF 1000000000
    
    
    using namespace std;
    
    int cost[1000], value[1000], n, X, dp[1000][1000];
    
    int solve(int idx, int val){
        if(idx == n){
            //this is the base case of the recursion, i.e when
            //the value is >= X then only we consider the solution
            //else we reject the solution and pass Infinity
            if(val >= X) return 0;
            else return INF;
        }
        //this is the step where we return the solution if we have calculated it previously
        //when dp[idx][val] == -1, that means that the solution has not been calculated before
        //and we need to calculate it now
        if(dp[idx][val] != -1) return dp[idx][val];
    
        //this is the step where we do not pick the current element in the knapsack
        int v1 = solve(idx+1, val);
    
        //this is the step where we add the current element in the knapsack
        int v2 = solve(idx+1, val + value[idx]) + cost[idx];
    
        //here we are taking the minimum of the above two choices that we made and trying
        //to find the better one, i.e the one which is the minimum
        int ans = min(v1, v2);
    
        //here we are setting the answer, so that if we find this state again, then we do not calculate
        //it again rather use this solution that we calculated
        dp[idx][val] = ans;
    
        return dp[idx][val];
    }
    
    int main(){
        cin >> n >> X;
        for(int i = 0;i < n;i++){
            cin >> cost[i] >> value[i];
        }
    
        //here we are initializing our dp table to -1, i.e no state has been calculated currently
        memset(dp, -1, sizeof dp);
    
        int ans = solve(0, 0);
    
        //if the answer is Infinity then the solution is not possible
        if(ans != INF)cout << solve(0, 0) << endl;
        else cout << "IMPOSSIBLE" << endl;
    
        return 0;
    }
    

    ideone 上的解决方案链接:http://ideone.com/7ZCW8z

    【讨论】:

    • 我不确定我是否完全理解您的解决方案,因为我不太精通 C++,但它似乎确实有效。你能解释一下你在这里做什么吗? if(dp[idx][val] != -1) return dp[idx][val]; int v = solve(idx+1, val); v = min(v, solve(idx+1, val + value[idx]) + cost[idx]); return dp[idx][val] = v;
    • @Luca Giorgi 我已将 cmets 添加到解决方案中,以便正确解释,您可能需要查找 recursive dynamic programming 以更好地了解解决方案。
    猜你喜欢
    • 1970-01-01
    • 2017-03-22
    • 2013-09-19
    • 2018-05-16
    • 2021-01-28
    • 1970-01-01
    • 2016-12-24
    • 2018-05-21
    • 1970-01-01
    相关资源
    最近更新 更多