Given an integer W, arrays val[] and wt[], where val[i] and wt[i] are the values and weights of the ith item, the task is to calculate the maximum value that can be obtained using weights not exceeding W.
Note: Each weight can be included multiple times.
Examples:
Input: W = 4, val[] = {6, 18}, wt[] = {2, 3}
Output: 18
Explanation: The maximum value that can be obtained is 18, by selecting the 2nd item twice.Input: W = 50, val[] = {6, 18}, wt[] = {2, 3}
Output: 294
Naive Approach: Refer to the previous post to solve the problem using traditional Unbounded Knapsack algorithm.
Time Complexity: O(N * W)
Auxiliary Space: O(W)
Efficient Approach: The above approach can be optimized based on the following observations:
- Suppose the ith index gives us the maximum value per unit weight in the given data, which can be easily found in O(n).
- For any weight X, greater than or equal to wt[i], the maximum reachable value will be dp[X – wt[i]] + val[i].
- We can calculate the values of dp[] from 0 to wt[i] using the traditional algorithm and we can also calculate the number of instances of ith item we can fit in W weight.
- So the required answer will be val[i] * (W/wt[i]) + dp[W%wt[i]].
Below is the implementation of new algorithm.
C++
// C++ program to implement optimized Unbounded Knapsack // algorithm #include <bits/stdc++.h> using namespace std; // Function to implement optimized // Unbounded Knapsack algorithm int unboundedKnapsackBetter( int W, vector< int > val, vector< int > wt) { // Stores most dense item int maxDenseIndex = 0; // Find the item with highest unit value // (if two items have same unit value then choose the // lighter item) for ( int i = 1; i < val.size(); i++) { if (val[i] / wt[i] > val[maxDenseIndex] / wt[maxDenseIndex] || (val[i] / wt[i] == val[maxDenseIndex] / wt[maxDenseIndex] && wt[i] < wt[maxDenseIndex])) { maxDenseIndex = i; } } int dp[W + 1] = { 0 }; int counter = 0; bool breaked = false ; int i = 0; for (i = 0; i <= W; i++) { for ( int j = 0; j < wt.size(); j++) { if (wt[j] <= i) { dp[i] = max(dp[i], dp[i - wt[j]] + val[j]); } } if (i - wt[maxDenseIndex] >= 0 && dp[i] - dp[i - wt[maxDenseIndex]] == val[maxDenseIndex]) { counter += 1; if (counter >= wt[maxDenseIndex]) { breaked = true ; break ; } } else { counter = 0; } } if (!breaked) { return dp[W]; } else { int start = i - wt[maxDenseIndex] + 1; int times = ( floor )((W - start) / wt[maxDenseIndex]); int index = (W - start) % wt[maxDenseIndex] + start; return (times * val[maxDenseIndex] + dp[index]); } } // Driver Code int main() { int W = 100; vector< int > val = { 10, 30, 20 }; vector< int > wt = { 5, 10, 15 }; cout << unboundedKnapsackBetter(W, val, wt); } // This code is contributed by ratiagrawal. |
Java
import java.io.*; import java.lang.*; import java.util.*; // class to implement optimized Unbounded Knapsack algorithm class Main { // function to implement optimized Unbounded Knapsack // algorithm public static int unboundedKnapsackBetter( int W, int [] val, int [] wt) { // find the item with highest unit value int maxDenseIndex = 0 ; for ( int i = 1 ; i < val.length; i++) { if (val[i] / wt[i] > val[maxDenseIndex] / wt[maxDenseIndex] || (val[i] / wt[i] == val[maxDenseIndex] / wt[maxDenseIndex] && wt[i] < wt[maxDenseIndex])) { maxDenseIndex = i; } } int [] dp = new int [W + 1 ]; int counter = 0 ; boolean breaked = false ; int i = 0 ; // dynamic programming step for (i = 0 ; i <= W; i++) { for ( int j = 0 ; j < wt.length; j++) { if (wt[j] <= i) { dp[i] = Math.max(dp[i], dp[i - wt[j]] + val[j]); } } if (i - wt[maxDenseIndex] >= 0 && dp[i] - dp[i - wt[maxDenseIndex]] == val[maxDenseIndex]) { counter += 1 ; if (counter >= wt[maxDenseIndex]) { breaked = true ; break ; } } else { counter = 0 ; } } if (!breaked) { return dp[W]; } else { int start = i - wt[maxDenseIndex] + 1 ; int times = ( int )((W - start) / wt[maxDenseIndex]); int index = (W - start) % wt[maxDenseIndex] + start; return (times * val[maxDenseIndex] + dp[index]); } } // Driver Code public static void main(String[] args) { int W = 100 ; int [] val = { 10 , 30 , 20 }; int [] wt = { 5 , 10 , 15 }; System.out.println( unboundedKnapsackBetter(W, val, wt)); } } |
Python3
# Python Program to implement the above approach from fractions import Fraction # Function to implement optimized # Unbounded Knapsack algorithm def unboundedKnapsackBetter(W, val, wt): # Stores most dense item maxDenseIndex = 0 # Find the item with highest unit value # (if two items have same unit value then choose the lighter item) for i in range ( 1 , len (val)): if Fraction(val[i], wt[i]) \ > Fraction(val[maxDenseIndex], wt[maxDenseIndex]) \ or (Fraction(val[i], wt[i]) = = Fraction(val[maxDenseIndex], wt[maxDenseIndex]) and wt[i] < wt[maxDenseIndex]): maxDenseIndex = i dp = [ 0 for i in range (W + 1 )] counter = 0 breaked = False for i in range (W + 1 ): for j in range ( len (wt)): if (wt[j] < = i): dp[i] = max (dp[i], dp[i - wt[j]] + val[j]) if i - wt[maxDenseIndex] > = 0 \ and dp[i] - dp[i - wt[maxDenseIndex]] = = val[maxDenseIndex]: counter + = 1 if counter > = wt[maxDenseIndex]: breaked = True # print(i) break else : counter = 0 if not breaked: return dp[W] else : start = i - wt[maxDenseIndex] + 1 times = (W - start) / / wt[maxDenseIndex] index = (W - start) % wt[maxDenseIndex] + start return (times * val[maxDenseIndex] + dp[index]) # Driver Code W = 100 val = [ 10 , 30 , 20 ] wt = [ 5 , 10 , 15 ] print (unboundedKnapsackBetter(W, val, wt)) |
C#
// C# program to implement optimized Unbounded Knapsack // algorithm using System; public class GFG { // function to implement optimized Unbounded Knapsack // algorithm static int unboundedKnapsackBetter( int W, int [] val, int [] wt) { // find the item with highest unit value int maxDenseIndex = 0; for ( int j = 1; j < val.Length; j++) { if (val[j] * 1.0 / wt[j] > val[maxDenseIndex] * 1.0 / wt[maxDenseIndex] || (val[j] * 1.0 / wt[j] == val[maxDenseIndex] * 1.0 / wt[maxDenseIndex] && wt[j] < wt[maxDenseIndex])) { maxDenseIndex = j; } } int [] dp = new int [W + 1]; int counter = 0; bool breaked = false ; int x = 0; // dynamic programming step for (; x <= W; x++) { for ( int j = 0; j < wt.Length; j++) { if (wt[j] <= x) { dp[x] = Math.Max(dp[x], dp[x - wt[j]] + val[j]); } } if (x - wt[maxDenseIndex] >= 0 && dp[x] - dp[x - wt[maxDenseIndex]] == val[maxDenseIndex]) { counter++; if (counter >= wt[maxDenseIndex]) { breaked = true ; break ; } } else { counter = 0; } } if (!breaked) { return dp[W]; } else { int start = x - wt[maxDenseIndex] + 1; int times = (W - start) / wt[maxDenseIndex]; int index = (W - start) % wt[maxDenseIndex] + start; return (times * val[maxDenseIndex] + dp[index]); } } static public void Main() { // Code int W = 100; int [] val = { 10, 30, 20 }; int [] wt = { 5, 10, 15 }; Console.WriteLine( unboundedKnapsackBetter(W, val, wt)); } } // This code is contributed by karthik. |
Javascript
// JavaScript program to implement optimized Unbounded Knapsack algorithm // Function to implement optimized // Unbounded Knapsack algorithm function unboundedKnapsackBetter(W, val, wt) { // Stores most dense item let maxDenseIndex = 0 // Find the item with highest unit value // (if two items have same unit value then choose the lighter item) for (let i = 1; i < val.length; i++) { if (val[i] / wt[i] > val[maxDenseIndex] / wt[maxDenseIndex] || (val[i] / wt[i] === val[maxDenseIndex] / wt[maxDenseIndex] && wt[i] < wt[maxDenseIndex])) { maxDenseIndex = i; } } let dp = new Array(W + 1).fill(0); let counter = 0; let breaked = false ; for ( var i = 0; i <= W; i++) { for (let j = 0; j < wt.length; j++) { if (wt[j] <= i) { dp[i] = Math.max(dp[i], dp[i - wt[j]] + val[j]); } } if (i - wt[maxDenseIndex] >= 0 && dp[i] - dp[i - wt[maxDenseIndex]] === val[maxDenseIndex]) { counter += 1; if (counter >= wt[maxDenseIndex]) { breaked = true ; break ; } } else { counter = 0; } } if (!breaked) { return dp[W]; } else { let start = i - wt[maxDenseIndex] + 1; let times = Math.floor((W - start) / wt[maxDenseIndex]); let index = (W - start) % wt[maxDenseIndex] + start; return (times * val[maxDenseIndex] + dp[index]); } } // Driver Code let W = 100; let val = [10, 30, 20]; let wt = [5, 10, 15]; console.log(unboundedKnapsackBetter(W, val, wt)); // This code is contributed by lokeshpotta20. |
300
Time Complexity: O( N + min(wt[i], W) * N)
Auxiliary Space: O(W)
Ready to dive in? Explore our Free Demo Content and join our DSA course, trusted by over 100,000 neveropen!