多重约束背包

时间:2017-12-07 17:00:18

标签: c++ algorithm dynamic-programming backtracking knapsack-problem

我试图解决以下问题:

INPUT:

  1. 一系列商品,每件商品都有 3种不同的权重(整数),一个值此类商品的可用金额
  2. 每种重量的最大值
  3. 输出:

    1. 一个数组,它告诉每个项目需要多少才能达到最大值。每个项目的每个权重的总和不得超过允许的最大值,您可能不会获取更多可用项目。
    2. 示例输出:{3,0,2,1}表示item1中的3个,item2中的0个,item3中的2个以及item4中的1个。

      示例场景:

      如果我对解释不是很清楚,想象一下将食物放在背包上。每种类型的食物都具有重量,体积,卡路里数量和价值,并且每种类型的食物都有一定数量。目标是最大化背包中的食物价值,而不超过一定的最大重量,体积和卡路里。

      在这种情况下, INPUT 可以是:

      Array<Food>:
      
      • 汉堡(体重2,第2卷,卡路里5,价值5 $ ,汉堡3号)
      • 披萨(体重3,第7卷,卡路里6,价值8 $ ,比萨饼数量2)
      • 热狗(体重1,体积1,卡路里3,价值2 $ ,热狗数量6)

      int MaxWeight = 10; int MaxVolume = 15; int MaxCalories = 10;

      我的尝试

      由于数据集非常小(比如7种类型的项目,并且每个项目不超过15件),我想到了一个强力搜索:

      • 跟踪到目前为止找到的最佳设置(最有价值且没有 超过任何限制),拨打最佳集 B
      • 有一个递归函数R(s),它接受​​一个集合(每个项目中有多少个数组)作为输入,如果输入无效,则返回。如果输入有效,则首先更新 B (如果s优于 B ),然后为每个产品调用R(s + p_i) p_i

      我们的想法是首先使用s =空集(每个产品为0)调用R(s),并且将创建每个可能的分支,同时忽略超出权重的分支。

      这显然没有用,因为即使只有少数7项,必须检查的分支数量也很大

      非常感谢任何帮助!

1 个答案:

答案 0 :(得分:2)

您必须在DP方法中考虑每种类型的重量。我将用C ++编写实现:

vector<Food> Array;
int memo[MAX_ITEM][MAX_WEIGHT1][MAX_WEIGHT2][MAX_WEIGHT3];
int f(int ind, int weight1, int weight2, int weight3){
    if(weight1<0 || weight2<0 || weight3<0) return -INF;
    if(ind == Array.size()) return 0;
    int &ret= memo[ind][weight1][weight2][weight3];
    if(ret>0) return ret;
    int res = 0;
    for(int i=0;i<=Array[ind].maxOfType;i++)
        res = max(res, i * Array[ind].value + f(ind+1, weight1-i*Array[ind].weight1, weight2-i*Array[ind].weight2, weight3-i*Array[ind].weight3));
    return ret = res;
}

DP函数是递归的,我们使用memoization来优化它。它返回我们可以得到的最大值。你可以通过以下方式来打电话:

f(0,MaxWeight1, MaxWeight2, MaxWeight3);

之后我们必须跟踪并查看哪些项目具有最大价值。 Next方法将打印您想要的内容:

void printResult(int ind, int weight1, int weight2, int weight3){
        if(ind == Array.size()) return;
        int maxi = memo[ind][weight1][weight2][weight3];
        for(int i=0;i<=Array[ind].maxOfType;i++){
            int cur = i * Array[ind].value + f(ind+1, weight1-i*Array[ind].weight1, weight2-i*Array[ind].weight2, weight3-i*Array[ind].weight3);
            if(cur == maxi){
                cout<<i<<", ";
                printResult(ind+1, weight1-i*Array[ind].weight1, weight2-i*Array[ind].weight2, weight3-i*Array[ind].weight3);
                break;
            }
        }
}

所有代码都经过测试并且运行良好。

相关问题