两个包的背包算法

Posted

技术标签:

【中文标题】两个包的背包算法【英文标题】:Knapsack algorithm for two bags 【发布时间】:2013-11-27 23:47:25 【问题描述】:

我找到了thread,它为带有 2 个背包的背包算法提供了伪代码。 我已经尝试在 C++ 中实现它,但它不像假设的那样工作。代码如下:

#include <cstdio>
#define MAX_W1 501
#define MAX_W2 501

int maximum(int a, int b, int c) 
    int max = a>b?a:b;
    return c>max?c:max;


int knapsack[MAX_W1][MAX_W2] = 0;

int main() 
    int n, s1, s2, gain, weight; // items, sack1, sack2, gain, cost

    scanf("%d %d %d", &n, &s1, &s2);

    // filing knapsack
    for (int i = 0; i < n; i++) 
        scanf("%d %d", &gain, &weight);

        for (int w1 = s1; w1 >= weight; w1--) 
            for (int w2 = s2; w2 >= weight; w2--) 
                knapsack[w1][w2] = maximum(
                    knapsack[w1][w2],                 // we have best option
                    knapsack[w1 - weight][w2] + gain, // put into sack one
                    knapsack[w1][w2 - weight] + gain  // put into sack two
                );
            
        
    

    int result = 0;

    // searching for result
    for (int i = 0; i <= s1; i++) 
        for (int j = 0; j <= s2; j++) 
            if (knapsack[i][j] > result) 
                result = knapsack[i][j];
            
        
    

    printf("%d\n", result);

    return 0;

例如以下输入:

5 4 3
6 2
3 2
4 1
2 1
1 1

我有输出:

13

显然这是错误的,因为我可以将所有物品(1,2 放入第一个袋子,其余放入第二个袋子),总和为 16。 如果我得到伪代码错误的任何解释,我将不胜感激。

我几乎没有更新,因为有些人在理解输入格式方面有问题:

    第一行包含 3 个数字,分别是物品数量、一袋容量、二袋容量 后来有 n 行,每行包含 2 个数字:增益,第 i 个项目的成本。 假设麻袋不能大于 500。

【问题讨论】:

【参考方案1】:

您使用的算法似乎不正确,因为它只会考虑对象恰好适合两个麻袋的情况。我对您的代码进行了以下更改,它现在可以正常运行:

#include <algorithm>

using std::max;

int max3(int a, int b, int c) 
    return max(a, max(b, c));

for (int w1 = s1; w1 >= 0; w1--) 
    for (int w2 = s2; w2 >= 0; w2--) 
        if (w1 >= weight && w2 >= weight) // either sack has room
        
            knapsack[w1][w2] = max3(
                knapsack[w1][w2],                 // we have best option
                knapsack[w1 - weight][w2] + gain, // put into sack one
                knapsack[w1][w2 - weight] + gain  // put into sack two
            );
        
        else if (w1 >= weight) // only sack one has room
        
            knapsack[w1][w2] = max(
                knapsack[w1][w2],                 // we have best option
                knapsack[w1 - weight][w2] + gain  // put into sack one
            );
        
        else if (w2 >= weight) // only sack two has room
        
            knapsack[w1][w2] = max(
                knapsack[w1][w2],                 // we have best option
                knapsack[w1][w2 - weight] + gain  // put into sack two
            );
        
    

【讨论】:

感谢您的回答,因为它首先是正确的,并解释为什么算法不正确。事实上,当我想到它时,我真的很怀念那个案例。 当没有一个麻袋有足够的容量(尽管 >0)来适应重量时会发生什么。我认为需要考虑这种情况。【参考方案2】:

这里是修改代码以使其工作:-

#include <cstdio>
#define MAX_W1 501
#define MAX_W2 501

int maximum(int a, int b, int c) 
    int max = a>b?a:b;
    return c>max?c:max;


int knapsack[MAX_W1][MAX_W2] = 0;

int main() 
    int n, s1, s2, gain, weight; // items, sack1, sack2, gain, cost

    scanf("%d %d %d", &n, &s1, &s2);

    // filing knapsack
    for (int i = 0; i < n; i++) 
        scanf("%d %d", &gain, &weight);
    // need to fill up all the table cannot stop if one sack is full because item might fit in other
        for (int w1 = s1; w1 >= 0; w1--) 
            for (int w2 = s2; w2 >= 0; w2--) 
                 int val1=0,val2=0;
                 if(weight<=w1)
                   val1 = knapsack[w1 - weight][w2] + gain;
                 if(weight<=w2)
                   val2 = knapsack[w1][w2 - weight] + gain;

                 knapsack[w1][w2] = maximum(
                    knapsack[w1][w2],                   // we have best option
                     val1,              // put into sack one
                     val2               // put into sack two
                  );


            
        
    


    // No need to search for max value it always be Knapsack[s1][s2]
    printf("%d\n", knapsack[s1][s2]);

    return 0;

【讨论】:

+1 用于在数组中查找答案时进行优化。 非常需要对代码的作用进行一些解释。 您如何能够跟踪放入每个麻袋的物品? 0-1 问题使用第一个维度来跟踪 n,但在这种情况下它被替换为 w1。我尝试了一个 3d 数组,但我不确定如何将 n 合并到上述算法中。 @Bendrix 您需要在数组中添加另一个索引以保存 n x w1 x w2 中的所有前 n 个项目,因为原始问题只是获得最大值,而与所选项目无关通过替换以前的选择,因为我们只关心最后 n-1 个项目的最大值。在您的情况下,您可以在每次外循环迭代后递增 i 并使用上述逻辑计算 knapsack[i][w1][w2] ,而在检索答案时,您必须从 knapsack[n-1][w1][w2 ] 到并选择 i 如果 knapsack[i-1][w1-w[i]] [w2] 或 knapsack[i-1][w1][w2 - w[i]] + w[i] > knapsack[i -1][w1][w2]。

以上是关于两个包的背包算法的主要内容,如果未能解决你的问题,请参考以下文章

急!动态规划 多人背包问题

算法学习——贪心算法之可拆背包

算法随笔一(背包问题)

算法---动态规划(背包问题分割回文串)

背包问题(贪心算法)

是否有按物品尺寸包装箱子的背包算法?