如何解决这个变种的背包问题?
你有n个物品(x1,...,xn),每个物品都有成本ci和价值vi(1<=i<=n),还有一个额外的限制X,它是所选项目价值的下限。 找到x1,...,xn的子集,使价值至少为X的物品的成本最小。
我试图通过动态规划来解决这个问题,我的想法是将通常使用的表格修改为K [n,c,X],其中X是我需要达到的最小值,但似乎没有什么效果。有什么好的建议吗?
如何解决这个变种的背包问题?
你有n个物品(x1,...,xn),每个物品都有成本ci和价值vi(1<=i<=n),还有一个额外的限制X,它是所选项目价值的下限。 找到x1,...,xn的子集,使价值至少为X的物品的成本最小。
我试图通过动态规划来解决这个问题,我的想法是将通常使用的表格修改为K [n,c,X],其中X是我需要达到的最小值,但似乎没有什么效果。有什么好的建议吗?
想出一种方法来将问题简化为最初的背包问题。
首先,假设您已经在解决方案中包含了所有项目。您的成本是Cost_Max,实现的价值是Val_Max(应该>= X才能存在解决方案)。
现在,回想一下最初的背包问题:给定一组带有权重W(i)和价值V(i)的物品,找到权重限制为w时的最大可达值。
现在,我们将使用这个背包问题来找到所有不包含在我们答案集中的项目。
因此,在计算您的问题中的Cost_Max和Val_Max之后,您必须将:
这将为您提供可以删除的最大成本,同时您的价值仍然>= X。
因此,如果从上一步中找到的成本为Cost_Knapsack,则您的答案为Cost_Max - Cost_Knapsack。
#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