Unbounded Knapsack (Repetition of items allowed) | Efficient Approach

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 algorithmint 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 Codeint 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 algorithmclass 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 CodeW = 100val = [10, 30, 20]wt = [5, 10, 15]Â
print(unboundedKnapsackBetter(W, val, wt)) |
C#
// C# program to implement optimized Unbounded Knapsack// algorithmusing 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 algorithmfunction 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 Codelet 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 zambiatek!



