Wednesday, July 3, 2024
HomeData ModellingDynamic ProgrammingUnbounded Knapsack (Repetition of items allowed) | Efficient Approach

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

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)

Feeling lost in the world of random DSA topics, wasting time without progress? It’s time for a change! Join our DSA course, where we’ll guide you on an exciting journey to master DSA efficiently and on schedule.
Ready to dive in? Explore our Free Demo Content and join our DSA course, trusted by over 100,000 neveropen!

Dominic Rubhabha Wardslaus
Dominic Rubhabha Wardslaushttps://neveropen.dev
infosec,malicious & dos attacks generator, boot rom exploit philanthropist , wild hacker , game developer,
RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Most Popular

Recent Comments