Unbounded Knapsack (Repetition of items allowed) | Efficient Approach
Last Updated :
26 May, 2023
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++
#include <bits/stdc++.h>
using namespace std;
int unboundedKnapsackBetter( int W, vector< int > val,
vector< int > wt)
{
int maxDenseIndex = 0;
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]);
}
}
int main()
{
int W = 100;
vector< int > val = { 10, 30, 20 };
vector< int > wt = { 5, 10, 15 };
cout << unboundedKnapsackBetter(W, val, wt);
}
|
Java
import java.io.*;
import java.lang.*;
import java.util.*;
class Main {
public static int
unboundedKnapsackBetter( int W, int [] val, int [] wt)
{
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 ;
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]);
}
}
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
from fractions import Fraction
def unboundedKnapsackBetter(W, val, wt):
maxDenseIndex = 0
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
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])
W = 100
val = [ 10 , 30 , 20 ]
wt = [ 5 , 10 , 15 ]
print (unboundedKnapsackBetter(W, val, wt))
|
C#
using System;
public class GFG {
static int unboundedKnapsackBetter( int W, int [] val,
int [] wt)
{
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;
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()
{
int W = 100;
int [] val = { 10, 30, 20 };
int [] wt = { 5, 10, 15 };
Console.WriteLine(
unboundedKnapsackBetter(W, val, wt));
}
}
|
Javascript
function unboundedKnapsackBetter(W, val, wt) {
let maxDenseIndex = 0
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]);
}
}
let W = 100;
let val = [10, 30, 20];
let wt = [5, 10, 15];
console.log(unboundedKnapsackBetter(W, val, wt));
|
Time Complexity: O( N + min(wt[i], W) * N)
Auxiliary Space: O(W)
Like Article
Suggest improvement
Share your thoughts in the comments
Please Login to comment...