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 once.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++ 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.
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));
}
}
# 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# 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 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)