Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ implementation of knapsack branch and bound

I am trying to a C++ implementation of this knapsack problem using branch and bounding. There is a Java version on this website here: Implementing branch and bound for knapsack

I'm trying to make my C++ version print out the 90 that it should, however it's not doing that, instead, it's printing out 5.

Does anyone know where and what the problem may be?

#include <queue>
#include <iostream>
using namespace std;

struct node
{
    int level;
    int profit;
    int weight;
    int bound;
};

int bound(node u, int n, int W, vector<int> pVa, vector<int> wVa)
{
    int j = 0, k = 0;
    int totweight = 0;
    int result = 0;

    if (u.weight >= W)
    {
        return 0;
    }
    else
    {
        result = u.profit;
        j = u.level + 1;
        totweight = u.weight;

        while ((j < n) && (totweight + wVa[j] <= W))
        {
            totweight = totweight + wVa[j];
            result = result + pVa[j];
            j++;
        }

        k = j;

        if (k < n)
        {
            result = result + (W - totweight) * pVa[k]/wVa[k];
        }
        return result;
    }
}

int knapsack(int n, int p[], int w[], int W)
{
    queue<node> Q;
    node u, v;
    vector<int> pV;
    vector<int> wV;
    Q.empty();

    for (int i = 0; i < n; i++)
    {
        pV.push_back(p[i]);
        wV.push_back(w[i]);
    }

    v.level = -1; 
    v.profit = 0;
    v.weight = 0;

    int maxProfit = 0;

    //v.bound = bound(v, n, W, pV, wV);
    Q.push(v);

    while (!Q.empty())
    {
        v = Q.front();
        Q.pop();

        if (v.level == -1)
        {
            u.level = 0;
        }
        else if (v.level != (n - 1))
        {
            u.level = v.level + 1;
        }

        u.weight = v.weight + w[u.level];
        u.profit = v.profit + p[u.level];

        u.bound = bound(u, n, W, pV, wV);

        if (u.weight <= W && u.profit > maxProfit)
        {
            maxProfit = u.profit;
        }

        if (u.bound > maxProfit)
        {
            Q.push(u);
        }

        u.weight = v.weight;
        u.profit = v.profit;

        u.bound = bound(u, n, W, pV, wV);

        if (u.bound > maxProfit)
        {
            Q.push(u);
        }
    }
    return maxProfit;
}

int main()
{
    int maxProfit;
    int n = 4;
    int W = 16;
    int p[4] = {2, 5, 10, 5};
    int w[4] = {40, 30, 50, 10};

    cout << knapsack(n, p, w, W) << endl;

    system("PAUSE");
}
like image 726
user1527877 Avatar asked Jul 16 '12 04:07

user1527877


People also ask

Is knapsack branch and bound?

Branch and bound is an algorithm design paradigm which is generally used for solving combinatorial optimization problems. These problems typically exponential in terms of time complexity and may require exploring all possible permutations in worst case.

Which branch and bound method is used to solve 0 1 knapsack?

As 0/1 Knapsack is about maximizing the total value, we cannot directly use the LC Branch and Bound technique to solve this. Instead, we convert this into a minimization problem by taking negative of the given values.

What is the time complexity of 0 to 1 knapsack problem using branch and & bound method?

Time Complexity- It takes θ(nw) time to fill (n+1)(w+1) table entries. It takes θ(n) time for tracing the solution since tracing process traces the n rows. Thus, overall θ(nw) time is taken to solve 0/1 knapsack problem using dynamic programming.


2 Answers

I think you have put the profit and weight values in the wrong vectors. Change:

int p[4] = {2, 5, 10, 5};
int w[4] = {40, 30, 50, 10};

to:

int w[4] = {2, 5, 10, 5};
int p[4] = {40, 30, 50, 10};

and your program will output 90.

like image 91
Bowie Owens Avatar answered Sep 30 '22 00:09

Bowie Owens


I believe what you are implementing is not a branch & bound algorithm exactly. It is more like an estimation based backtracking if I have to match it with something.

The problem in your algorithm is the data structure that you are using. What you are doing is to simply first push all the first levels, and then to push all second levels, and then to push all third levels to the queue and get them back in their order of insertion. You will get your result but this is simply searching the whole search space.

Instead of poping the elements with their insertion order what you need to do is to branch always on the node which has the highest estimated bound. In other words you are always branching on every node in your way regardless of their estimated bounds. Branch & bound technique gets its speed benefit from branching on only one single node each time which is most probable to lead to the result (has the highest estimated value).

Example : In your first iteration assume that you have found 2 nodes with estimated values

node1: 110

node2: 80

You are pushing them both to your queue. Your queue became "n2-n1-head" In the second iteration you are pushing two more nodes after branching on node1:

node3: 100

node4: 95

and you are adding them to you queue as well("n4-n3-n2-head". There comes the error. In the next iteration what you are going to get will be node2 but instead it should be node3 which has the highest estimated value.

So if I don't miss something in your code both your implementation and the java implementation are wrong. You should rather use a priority queue (heap) to implement a real branch & bound.

like image 37
ralzaul Avatar answered Sep 30 '22 01:09

ralzaul