Open In App

Unbounded Knapsack (Repetition of items allowed) | Efficient Approach

Last Updated : 26 May, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

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

Recommended Practice

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.


Output:

300

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



Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads