Soroush
Soroush

Reputation: 561

Find which items are taken in knapsack

solving the knapsack problem recursively, I want to know which items (item's weight) are taken in the bag that gives the maximum value. so far I have this:

int MAX(int a, int b) { return (a > b) ? a : b ; }
int thief(int W, int weight[], int value[], int n)
{
    int a,b,c;
    //basecase:
    if(n == 0 || weight <= 0) return 0;
    // each item's weight can't be more than W:
    if(weight[n-1] > W){
        return thief(W, weight, value, n-1);}

    a=value[n-1] + thief(W-weight[n-1], weight, value, n-1);// a: nth item included
    b=thief(W, weight, value, n-1);// b:nth item not included
    c= MAX(a,b);//answer is the maximum of situation a and b
    if (c==a) { //if situation a occurs then nth item is included
        cout<<weight[n]<<endl;
    }
    return c;


 }

consider n=4 and maximum weight (W) = 30
let weights be : 30 10 20 5
and values : 100 50 60 10
but this code outputs: 20 5 20 10 5
I just want to output 10 and 20.
also I have tried to define a bool array with default values of false and its nth element changes to true if c==a occurs but this won't give the correct result as well.
I'm supposed to do it recursively.

Upvotes: 1

Views: 3871

Answers (2)

Ameer Baidusi
Ameer Baidusi

Reputation: 11

can you write the code in c? I wrote this but didn't work. (I think the difference is in the bold)

int knapSack(int W, int wt[], int val[], int n, int arr[])
{
    int x, y, c, j, arr1[50], arr2[50];
    // Base Case 
    if (n == 0 || W == 0)
        return 0;

    // If weight of the nth item is more than Knapsack capacity W, then 
    // this item cannot be included in the optimal solution 
    if (wt[n - 1] > W)
        return knapSack(W, wt, val, n - 1, arr2);

    // Return the maximum of two cases:  
    // x nth item included  
    // y not included 
    **arr1[n - 1] = val[n - 1];**
    x = val[n - 1] + knapSack(W - wt[n - 1], wt, val, n - 1, arr1);
    //copyArr(arr, out, n);
    y = knapSack(W, wt, val, n - 1, arr2);

    if (x > y)
        c = x;
    else
        c = y;

    if (c == x)
        for (j = 0; j < 50; j++)
            arr[j] = arr1[j];

    else
        for (j = 0; j < 50; j++)
            arr[j] = arr2[j];

    return c;
}

Upvotes: 0

4386427
4386427

Reputation: 44329

Your basic algorithm doesn't work. You can't do the printing while you test different combinations.

However, first you must fix a bug:

    cout<<weight[n-1]<<endl; // n-1 instead of n 

Your algorithm does this:

a = value[3] + thief(30-weight[3], weight, value, 3); // Use item 3
b = thief(30, weight, value, 3);                      // Don't use item 3

The second line will lead to

a = value[2] + thief(30-weight[2], weight, value, 2); // Use item 2
b = thief(30, weight, value, 2);                      // Don't use item 2

The second line will lead to

a = value[1] + thief(30-weight[1], weight, value, 1); // Use item 1
b = thief(30, weight, value, 1);                      // Don't use item 1

The second line will lead to

a = value[0] + thief(30-weight[0], weight, value, 0); // Use item 0
b = thief(30, weight, value, 0);                      // Don't use item 0

This causes

a = 30
b = 0

so your code will select item 0 and print 30 but that is a bug!

So as I stated in the start: You can't do the printing while you test different combinations.

Instead you need to keep track of which elements you use in the different combinations and only keep the "best".

I haven't tested the code below but I think you can do it like this (assuming your code calculates the best combination correctly):

#include <vector>

// The vector v is used for holding the index of the items selected.
// The caller must supply a vector containing the items included so far.
// This function will test whether item "n-1" shall be included or
// excluded. If item "n-1" is included the index is added to the vector.

int thief(int W, int weight[], int value[], int n, vector<int>& v) // Added vector
{
    vector<int> v1, v2; // Vector to hold elements of the two combinations
    int a,b,c;
    //basecase:
    if(n == 0 || weight <= 0) return 0;
    // each item's weight can't be more than W:
    if(weight[n-1] > W){
        return thief(W, weight, value, n-1, v2);}

    v1.push_back(n-1); // Put n-1 in vector v1 and pass the vector v1
    a=value[n-1] + thief(W-weight[n-1], weight, value, n-1, v1);// a: nth item included

    // Don't put anything in v2 but pass the vector v2
    b=thief(W, weight, value, n-1, v2);// b:nth item not included
    c= MAX(a,b);//answer is the maximum of situation a and b
    if (c==a) { //if situation a occurs then nth item is included

//            cout<<weight[n-1]<<endl;

        // Copy elements from v1 to v
        for (auto e : v1)
        {
                v.push_back(e);
        }
    }
    else
    {
        // Copy elements from v2 to v
        for (auto e : v2)
        {
                v.push_back(e);
        }
    }
    return c;


 } 

int main() {
    vector<int> v;
    int weight[4] = {30, 10, 20, 5};
    int value[4] = {100, 50, 60, 10};
    cout << "result=" << thief(30, weight, value, 4, v) << endl;

    // Print the elements used
    for (auto e : v)
    {
        cout << "elem=" << e << endl;
    }
    return 0;
}

Finally notice - your brute force method is very expensive in terms of execution time in the start value for n is high. There are much better ways to solve this problem.

Upvotes: 3

Related Questions