0/1 Knapsack (medium)
Introduction
Given the weights and profits of ‘N’ items, we are asked to put these items in a knapsack with a capacity ‘C.’ The goal is to get the maximum profit out of the knapsack items. Each item can only be selected once, as we don’t have multiple quantities of any item.
Let’s take Merry’s example, who wants to carry some fruits in the knapsack to get maximum profit. Here are the weights and profits of the fruits:
Items: { Apple, Orange, Banana, Melon }
Weights: { 2, 3, 1, 4 }
Profits: { 4, 5, 3, 7 }
Knapsack capacity: 5
Let’s try to put various combinations of fruits in the knapsack, such that their total weight is not more than 5:
Apple + Orange (total weight 5) => 9 profit
Apple + Banana (total weight 3) => 7 profit
Orange + Banana (total weight 4) => 8 profit
Banana + Melon (total weight 5) => 10 profit
This shows that Banana + Melon is the best combination as it gives us the maximum profit, and the total weight does not exceed the capacity.
Problem Statement
Given two integer arrays to represent weights and profits of ‘N’ items, we need to find a subset of these items which will give us maximum profit such that their cumulative weight is not more than a given number ‘C.’ Each item can only be selected once, which means either we put an item in the knapsack or we skip it.
Try it yourself
Try solving this question here:
class Knapsack {public int solveKnapsack(int[] profits, int[] weights, int capacity) {// TODO: Write your code herereturn -1;}public static void main(String[] args) {Knapsack ks = new Knapsack();int[] profits = {1, 6, 10, 16};int[] weights = {1, 2, 3, 5};int maxProfit = ks.solveKnapsack(profits, weights, 7);System.out.println("Total knapsack profit ---> " + maxProfit);maxProfit = ks.solveKnapsack(profits, weights, 6);System.out.println("Total knapsack profit ---> " + maxProfit);}}
Basic Solution
A basic brute-force solution could be to try all combinations of the given items (as we did above), allowing us to choose the one with maximum profit and a weight that doesn’t exceed ‘C’. Take the example of four items (A, B, C, and D), as shown in the diagram below. To try all the combinations, our algorithm will look like:
for each item 'i'create a new set which INCLUDES item 'i' if the total weight does not exceed the capacity, andrecursively process the remaining capacity and itemscreate a new set WITHOUT item 'i', and recursively process the remaining itemsreturn the set from the above two sets with higher profit
Here is a visual representation of our algorithm:
All green boxes have a total weight that is less than or equal to the capacity (7), and all the red ones have a weight that is more than 7. The best solution we have is with items [B, D] having a total profit of 22 and a total weight of 7.
Code
Here is the code for the brute-force solution:
class Knapsack {public int solveKnapsack(int[] profits, int[] weights, int capacity) {return this.knapsackRecursive(profits, weights, capacity, 0);}private int knapsackRecursive(int[] profits, int[] weights, int capacity, int currentIndex) {// base checksif (capacity <= 0 || currentIndex >= profits.length)return 0;// recursive call after choosing the element at the currentIndex// if the weight of the element at currentIndex exceeds the capacity, we shouldn't process thisint profit1 = 0;if( weights[currentIndex] <= capacity )profit1 = profits[currentIndex] + knapsackRecursive(profits, weights,capacity - weights[currentIndex], currentIndex + 1);// recursive call after excluding the element at the currentIndexint profit2 = knapsackRecursive(profits, weights, capacity, currentIndex + 1);return Math.max(profit1, profit2);}public static void main(String[] args) {Knapsack ks = new Knapsack();int[] profits = {1, 6, 10, 16};int[] weights = {1, 2, 3, 5};int maxProfit = ks.solveKnapsack(profits, weights, 7);System.out.println("Total knapsack profit ---> " + maxProfit);maxProfit = ks.solveKnapsack(profits, weights, 6);System.out.println("Total knapsack profit ---> " + maxProfit);}}
Time and Space complexity
The above algorithm’s time complexity is exponential , where ‘n’ represents the total number of items. This can also be confirmed from the above recursion tree. As we can see, we will have a total of ‘31’ recursive calls – calculated through ...