
Data Structure
Networking
RDBMS
Operating System
Java
MS Excel
iOS
HTML
CSS
Android
Python
C Programming
C++
C#
MongoDB
MySQL
Javascript
PHP
- Selected Reading
- UPSC IAS Exams Notes
- Developer's Best Practices
- Questions and Answers
- Effective Resume Writing
- HR Interview Questions
- Computer Glossary
- Who is Who
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:
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).