3

I've found thread which provides pseudo-code for knapsack algorithm with 2 knapsacks. I've tried implement it in C++, but it doesn't work as suppose. Here's code:

#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;
}

For instance for following input:

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

I have output:

13

Obviously it's wrong because I can take all items (1,2 into first bag and rest to second bag) and sum is 16. I would be grateful for any explanation where I get pseudo-code wrong.

I made little update since, some people have problem with understanding the input format:

  1. First line contains 3 numbers as follows number of items, capacity of sack one, capacity of sack two
  2. Later on there are n lines where each contains 2 numbers: gain, cost of i-th item.
  3. Assume that sacks cannot be larger than 500.
Community
  • 1
  • 1
abc
  • 2,371
  • 3
  • 25
  • 36

2 Answers2

3

The algorithm you're using appears incorrect, because it will only consider cases where the object happens to fit in both sacks. I made the following changes to your code and it operates correctly now:

#include <algorithm>

using std::max;

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

and

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
            );
        }
    }
}
Joe Z
  • 17,413
  • 3
  • 28
  • 39
  • Appreciate your answer as it was first correct and give explanation why algorithm was incorrect. In fact when I think about it I really miss that case. – abc Nov 28 '13 at 09:41
  • 1
    What would happen when none of the sack has enough capacity (though >0) to fit the weight. I think that case needs to be considered. – rohan-patel Mar 19 '15 at 23:14
3

Here is modification to code to make it work:-

#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;
}
Vikram Bhat
  • 6,106
  • 3
  • 20
  • 19
  • +1 for optimization when it comes to finding answer in array. – abc Nov 28 '13 at 09:43
  • Some explanation about what the code is doing is strongly desirable. – Abhijit Sarkar Dec 25 '18 at 04:36
  • How would you be able to keep track of the items put into each sack? The 0-1 problem uses the first dimension to keep track of n, but in this case it is replaced with w1. Ive attempted a 3d array, but im not sure how to incorporate the n into the above algorithm. – Bendrix Oct 23 '20 at 03:06
  • @Bendrix You need to add another index in the array to save for all first n items in n by w1 by w2, as the original question was just getting the maximum value irrespective of the items selected it works by replacing previous choices as we only care about last n-1 item max values. In your case you can increment i after every iteration of outer loop and compute knapsack[i][w1][w2] using the above logic, while retrieving answer you have to work backwards from knapsack[n-1][w1][w2] to and select i if knapsack[i-1][w1-w[i]] [w2] or knapsack[i-1][w1][w2 - w[i]] + w[i] > knapsack[i-1][w1][w2]. – Vikram Bhat Oct 23 '20 at 13:16