0-1 Knapsack Problem Using Branch and Bound in C/C++



In the 0-1 knapsack problem, a set of items is given, each with a weight and a value. We need to determine the number of each item to include in a collection so that the total weight is less than or equal to the given limit and the total value is as large as possible.

What is Branch and Bound Algorithm?

The branch and bound algorithm breaks the given problem into multiple sub-problems and then uses a bounding function. It eliminates only those solutions that cannot provide optimal solutions.

In this article, we will discuss how to solve the 0-1 knapsack problem using branch and bound. We have weights and their profits, maximum capacity, and number of elements. Our task is to find the maximum profits with the given weight restriction using branch and bound in C/C++ Here is an example of a 0-1 knapsack problem using branch and bound:

Example

Input:
Weights: 1, 2, 3, 4
Profits: 10, 20, 25, 70
Maximum Weight Capacity: 7

Output:
Maximum Profit = 100

Here is the explanation of the above example using an image:

Branch and Bound image

C++ Implementation of 0-1 Knapsack Using Branch and Bound

We will be following these steps for implementing the 0-1 knapsack using branch and bound in C++:

  • We have used the struct data type to define Items that store the weight, value, and ratio.
  • The first for loop in the main() function calculates the ratio before sorting. We have used the sort() function for sorting.
  • Similarly, we have created nodes using the struct data type that represents the current weight, profit index, and bound.
  • Then we used the bound() function to calculate the upper bound. It makes use of fractional knapsack, which is later used in pruning.
  • Then we used a max-heap priority queue to explore nodes with higher profits first.
  • At each step, the branching happens by dividing the elements into included and excluded sections.
  • Then we select the nodes with higher profit than the current best profit. Repeat the process till the queue is empty.
  • In the end, the maxProfit is returned that stores the max profit with a given weight constraint.

Example

The following example implements the 0-1 knapsack problem using branch and bound method in C++:

#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>

using namespace std;

// Structure to represent an item
struct Item {
    int weight, value;
    double ratio;
};

// Representing a node in the state space tree
struct Node {
    int index, profit, weight;       
    double bound;    // Upper bound of maximum profit
};

// Compare nodes based on bound (for max-heap)
struct Compare {
    bool operator()(const Node& a, const Node& b) {
        return a.bound < b.bound;
    }
};

// Function to compute upper bound
double bound(Node u, int n, int w, const vector<Item>& items) {
    if (u.weight >= w) return 0;

    double profit_bound = u.profit;
    int j = u.index + 1;
    int totweight = u.weight;

    while (j < n && totweight + items[j].weight <= w) {
        totweight += items[j].weight;
        profit_bound += items[j].value;
        j++;
    }

    if (j < n) {
        profit_bound += (w - totweight) * items[j].ratio;
    }

    return profit_bound;
}


int ksBB(int w, vector<Item>& items, int n) {
    // Sort items by value/weight ratio in descending order
    sort(items.begin(), items.end(), [](Item a, Item b) {
        return a.ratio > b.ratio;
    });

    priority_queue<Node, vector<Node>, Compare> Q;
    Node u, v;
    u.index = -1;
    u.profit = 0;
    u.weight = 0;
    u.bound = bound(u, n, w, items);
    Q.push(u);

    int maxProfit = 0;

    while (!Q.empty()) {
        u = Q.top(); Q.pop();

        if (u.bound <= maxProfit) continue;

        v.index = u.index + 1;

        // Include the current item
        v.weight = u.weight + items[v.index].weight;
        v.profit = u.profit + items[v.index].value;

        if (v.weight <= w && v.profit > maxProfit) {
            maxProfit = v.profit;
        }

        v.bound = bound(v, n, w, items);
        if (v.bound > maxProfit)
            Q.push(v);

        // Exclude the current item
        v.weight = u.weight;
        v.profit = u.profit;
        v.bound = bound(v, n, w, items);
        if (v.bound > maxProfit)
            Q.push(v);
    }

    return maxProfit;
}

int main()
{
    int w = 7;
    vector<Item> items = {
        {1, 10, 0},
        {2, 20, 0},
        {3, 25, 0},
        {4, 70, 0}};
    int n = items.size();

    // Calculate value/weight ratio
    for (int i = 0; i < n; ++i)
        items[i].ratio = (double)items[i].value / items[i].weight;

    // Print weights and values
    cout << "Items (Weight, Profit):" << endl;
    for (const auto &item : items)
    {
        cout << "(" << item.weight << ", " << item.value << ")" << endl;
    }
    cout << "\nMax Weight Capacity: " << w << endl;
    // Print maximum profit
    cout << "Maximum Profit = " << ksBB(w, items, n) << endl;

    return 0;
}

The output of the above code is:

Items (Weight, Profit):
(1, 10)
(2, 20)
(3, 25)
(4, 70)

Max Weight Capacity: 7
Maximum Profit = 100

C Implementation of 0-1 Knapsack Using Branch and Bound

In the C implementation of the 0-1 knapsack problem using branch and bound, we have used a similar approach following the same steps as in the C++ implementation. The only difference is in the syntax as we have used the qsort() function for sorting in C, implemented a custom priority queue using an array, and used malloc() for dynamic memory allocation.

Example

Here is the C implementation of the 0-1 knapsack problem using branch and bound:

#include <stdio.h>
#include <stdlib.h>

typedef struct {
    int weight, value;
    double ratio;
} Item;

typedef struct {
    int index, profit, weight;
    double bound;
} Node;

// Comparison function for sorting items by value-to-weight ratio (descending)
int compare(const void* a, const void* b) {
    Item* i1 = (Item*)a;
    Item* i2 = (Item*)b;
    if (i2->ratio > i1->ratio) return 1;
    else if (i2->ratio < i1->ratio) return -1;
    return 0;
}

// Function to compute upper bound
double bound(Node u, int n, int w, Item items[]) {
    if (u.weight >= w) return 0;

    double profit_bound = u.profit;
    int j = u.index + 1;
    int totweight = u.weight;

    while (j < n && totweight + items[j].weight <= w) {
        totweight += items[j].weight;
        profit_bound += items[j].value;
        j++;
    }

    if (j < n)
        profit_bound += (w - totweight) * items[j].ratio;

    return profit_bound;
}

// Priority queue node for max-heap
typedef struct {
    Node* nodes;
    int size;
    int capacity;
} PriorityQueue;

PriorityQueue* createPQ(int capacity) {
    PriorityQueue* pq = (PriorityQueue*)malloc(sizeof(PriorityQueue));
    pq->nodes = (Node*)malloc(sizeof(Node) * capacity);
    pq->size = 0;
    pq->capacity = capacity;
    return pq;
}

void swap(Node* a, Node* b) {
    Node temp = *a;
    *a = *b;
    *b = temp;
}

void push(PriorityQueue* pq, Node node) {
    int i = pq->size++;
    pq->nodes[i] = node;
    while (i != 0 && pq->nodes[(i - 1) / 2].bound < pq->nodes[i].bound) {
        swap(&pq->nodes[i], &pq->nodes[(i - 1) / 2]);
        i = (i - 1) / 2;
    }
}

Node pop(PriorityQueue* pq) {
    Node top = pq->nodes[0];
    pq->nodes[0] = pq->nodes[--pq->size];
    int i = 0;
    while (2 * i + 1 < pq->size) {
        int largest = i;
        int left = 2 * i + 1;
        int right = 2 * i + 2;

        if (left < pq->size && pq->nodes[left].bound > pq->nodes[largest].bound)
            largest = left;
        if (right < pq->size && pq->nodes[right].bound > pq->nodes[largest].bound)
            largest = right;

        if (largest == i) break;
        swap(&pq->nodes[i], &pq->nodes[largest]);
        i = largest;
    }
    return top;
}

int isEmpty(PriorityQueue* pq) {
    return pq->size == 0;
}

int ksBB(int w, Item items[], int n) {
    qsort(items, n, sizeof(Item), compare);

    PriorityQueue* pq = createPQ(1000);
    Node u = {-1, 0, 0, 0};
    u.bound = bound(u, n, w, items);
    push(pq, u);

    int maxProfit = 0;

    while (!isEmpty(pq)) {
        u = pop(pq);

        if (u.bound <= maxProfit) continue;

        Node v;
        v.index = u.index + 1;

        // Include
        v.weight = u.weight + items[v.index].weight;
        v.profit = u.profit + items[v.index].value;
        if (v.weight <= w && v.profit > maxProfit)
            maxProfit = v.profit;

        v.bound = bound(v, n, w, items);
        if (v.bound > maxProfit)
            push(pq, v);

        // Exclude
        v.weight = u.weight;
        v.profit = u.profit;
        v.bound = bound(v, n, w, items);
        if (v.bound > maxProfit)
            push(pq, v);
    }

    free(pq->nodes);
    free(pq);
    return maxProfit;
}

int main() {
    int w = 7;
    Item items[] = {
        {1, 10, 0},
        {2, 20, 0},
        {3, 25, 0},
        {4, 70, 0}
    };
    int n = sizeof(items) / sizeof(items[0]);

    // Calculate ratios
    for (int i = 0; i < n; ++i)
        items[i].ratio = (double)items[i].value / items[i].weight;

    printf("Items (Weight, Profit):\n");
    for (int i = 0; i < n; ++i)
        printf("(%d, %d)\n", items[i].weight, items[i].value);

    printf("\nMax Weight Capacity: %d\n", w);
    printf("Maximum Profit = %d\n", ksBB(w, items, n));
    return 0;
}

The output of the above code is:

Items (Weight, Profit):
(1, 10)
(2, 20)
(3, 25)
(4, 70)

Max Weight Capacity: 7
Maximum Profit = 100

Complexity of 0-1 Knapsack Using Branch and Bound

  • Time Complexity: The time complexity of the 0-1 knapsack problem using branch and bound is O(2^n).
  • Space Complexity: The space complexity of the 0-1 knapsack problem using branch and bound is O(2^n).
Updated on: 2025-05-05T12:29:17+05:30

2K+ Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements