Skip to content
Related Articles

Related Articles

Unbounded Knapsack (Repetition of items allowed) | Set 2

View Discussion
Improve Article
Save Article
  • Difficulty Level : Medium
  • Last Updated : 21 Jul, 2021
View Discussion
Improve Article
Save Article

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
Explaination: 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.

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))

Output:

300

Time Complexity: O( N + min(wt[i], W) * N)
Auxiliary Space: O(W)


My Personal Notes arrow_drop_up
Recommended Articles
Page :

Start Your Coding Journey Now!