Given an integer array W[] consisting of weights of the items and some queries consisting of capacity C of knapsack, for each query find maximum weight we can put in the knapsack. Value of C doesn’t exceed a certain integer C_MAX.
Examples:
Input: W[] = {3, 8, 9} q = {11, 10, 4}
Output:
11
9
3
If C = 11: select 3 + 8 = 11
If C = 10: select 9
If C = 4: select 3
Input: W[] = {1, 5, 10} q = {6, 14}
Output:
6
11
Its recommended that you go through this article on 0-1 knapsack before attempting this problem.
Naive approach: For each query, we can generate all possible subsets of weight and choose the one that has maximum weight among all those subsets that fits in the knapsack. Thus, answering each query will take exponential time.
Efficient approach: We will optimize answering each query using dynamic programming.
0-1 knapsack is solved using 2-D DP, one state ‘i’ for current index(i.e select or reject) and one for remaining capacity ‘R’.
Recurrence relation is
dp[i][R] = max(arr[i] + dp[i + 1][R – arr[i]], dp[i + 1][R])
We will pre-compute the 2-d array dp[i][C] for every possible value of ‘C’ between 1 to C_MAX in O(C_MAX*i).
Using this, pre-computation we can answer each queries in O(1) time.
Below is the implementation of the above approach:
C++
#include <bits/stdc++.h>
#define C_MAX 30
#define max_arr_len 10
using namespace std;
int dp[max_arr_len][C_MAX + 1];
bool v[max_arr_len][C_MAX + 1];
int findMax( int i, int r, int w[], int n)
{
if (r < 0)
return INT_MIN;
if (i == n)
return 0;
if (v[i][r])
return dp[i][r];
v[i][r] = 1;
dp[i][r] = max(w[i] + findMax(i + 1, r - w[i], w, n),
findMax(i + 1, r, w, n));
return dp[i][r];
}
void preCompute( int w[], int n)
{
for ( int i = C_MAX; i >= 0; i--)
findMax(0, i, w, n);
}
int ansQuery( int w)
{
return dp[0][w];
}
int main()
{
int w[] = { 3, 8, 9 };
int n = sizeof (w) / sizeof ( int );
preCompute(w, n);
int queries[] = { 11, 10, 4 };
int q = sizeof (queries) / sizeof (queries[0]);
for ( int i = 0; i < q; i++)
cout << ansQuery(queries[i]) << endl;
return 0;
}
|
Java
class GFG
{
static int C_MAX = 30 ;
static int max_arr_len = 10 ;
static int dp [][] = new int [max_arr_len][C_MAX + 1 ];
static boolean v[][]= new boolean [max_arr_len][C_MAX + 1 ];
static int findMax( int i, int r, int w[], int n)
{
if (r < 0 )
return Integer.MIN_VALUE;
if (i == n)
return 0 ;
if (v[i][r])
return dp[i][r];
v[i][r] = true ;
dp[i][r] = Math.max(w[i] + findMax(i + 1 , r - w[i], w, n),
findMax(i + 1 , r, w, n));
return dp[i][r];
}
static void preCompute( int w[], int n)
{
for ( int i = C_MAX; i >= 0 ; i--)
findMax( 0 , i, w, n);
}
static int ansQuery( int w)
{
return dp[ 0 ][w];
}
public static void main (String[] args)
{
int w[] = new int []{ 3 , 8 , 9 };
int n = w.length;
preCompute(w, n);
int queries[] = new int [] { 11 , 10 , 4 };
int q = queries.length;
for ( int i = 0 ; i < q; i++)
System.out.println(ansQuery(queries[i]));
}
}
|
Python3
import numpy as np
import sys
C_MAX = 30
max_arr_len = 10
dp = np.zeros((max_arr_len,C_MAX + 1 ));
v = np.zeros((max_arr_len,C_MAX + 1 ));
INT_MIN = - (sys.maxsize) + 1
def findMax(i, r, w, n) :
if (r < 0 ) :
return INT_MIN;
if (i = = n) :
return 0 ;
if (v[i][r]) :
return dp[i][r];
v[i][r] = 1 ;
dp[i][r] = max (w[i] + findMax(i + 1 , r - w[i], w, n),
findMax(i + 1 , r, w, n));
return dp[i][r];
def preCompute(w, n) :
for i in range (C_MAX, - 1 , - 1 ) :
findMax( 0 , i, w, n);
def ansQuery(w) :
return dp[ 0 ][w];
if __name__ = = "__main__" :
w = [ 3 , 8 , 9 ];
n = len (w)
preCompute(w, n);
queries = [ 11 , 10 , 4 ];
q = len (queries)
for i in range (q) :
print (ansQuery(queries[i]));
|
C#
using System;
class GFG
{
static int C_MAX = 30;
static int max_arr_len = 10;
static int [,] dp = new int [max_arr_len, C_MAX + 1];
static bool [,] v = new bool [max_arr_len, C_MAX + 1];
static int findMax( int i, int r, int [] w, int n)
{
if (r < 0)
return Int32.MaxValue;
if (i == n)
return 0;
if (v[i, r])
return dp[i, r];
v[i, r] = true ;
dp[i, r] = Math.Max(w[i] + findMax(i + 1, r - w[i], w, n),
findMax(i + 1, r, w, n));
return dp[i, r];
}
static void preCompute( int [] w, int n)
{
for ( int i = C_MAX; i >= 0; i--)
findMax(0, i, w, n);
}
static int ansQuery( int w)
{
return dp[0, w];
}
public static void Main()
{
int [] w= { 3, 8, 9 };
int n = w.Length;
preCompute(w, n);
int [] queries = { 11, 10, 4 };
int q = queries.Length;
for ( int i = 0; i < q; i++)
Console.WriteLine(ansQuery(queries[i]));
}
}
|
Javascript
<script>
var C_MAX = 30
var max_arr_len = 10
var dp = Array.from(Array(max_arr_len), ()=>Array(C_MAX+1));
var v = Array.from(Array(max_arr_len), ()=>Array(C_MAX+1));
function findMax(i, r, w, n)
{
if (r < 0)
return -1000000000;
if (i == n)
return 0;
if (v[i][r])
return dp[i][r];
v[i][r] = 1;
dp[i][r] = Math.max(w[i] + findMax(i + 1, r - w[i], w, n),
findMax(i + 1, r, w, n));
return dp[i][r];
}
function preCompute(w, n)
{
for ( var i = C_MAX; i >= 0; i--)
findMax(0, i, w, n);
}
function ansQuery(w)
{
return dp[0][w];
}
var w = [3, 8, 9];
var n = w.length;
preCompute(w, n);
var queries = [11, 10, 4];
var q = queries.length;
for ( var i = 0; i < q; i++)
document.write( ansQuery(queries[i])+ "<br>" );
</script>
|
Efficient approach: Using DP Tabulation method ( Iterative approach )
The approach to solve this problem is same but DP tabulation(bottom-up) method is better then Dp + memoization(top-down) because memoization method needs extra stack space of recursion calls.
Steps to solve this problem :
- Create a DP to store the solution of the subproblems and initialize it with 0.
- Initialize the DP with base cases
- Now Iterate over subproblems to get the value of current problem form previous computation of subproblems stored in DP.
- After filling the DP now in Main function call every query and get the answer stored in DP.
Implementation :
C++
#include <bits/stdc++.h>
#define C_MAX 30
#define max_arr_len 10
using namespace std;
int dp[max_arr_len][C_MAX + 1] = {0};
void findMax( int w[], int n, int c)
{
for ( int i = 1; i <= n; i++) {
for ( int j = 1; j <= c; j++) {
if (w[i - 1] <= j) {
dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - w[i - 1]] + w[i - 1]);
}
else {
dp[i][j] = dp[i - 1][j];
}
}
}
return ;
}
int main()
{
int w[] = { 3, 8, 9 };
int n = sizeof (w) / sizeof ( int );
int queries[] = { 11, 10, 4 };
int q = sizeof (queries) / sizeof (queries[0]);
int ma = *max_element(queries, queries + q);
findMax(w, n , ma);
for ( int i = 0; i < q; i++)
cout << dp[n][queries[i]] << endl;
return 0;
}
|
Java
public class MaxSubsetSum {
static int [][] findMax( int [] w, int n, int c) {
int [][] dp = new int [n + 1 ];
for ( int i = 1 ; i <= n; i++) {
for ( int j = 1 ; j <= c; j++) {
if (w[i - 1 ] <= j) {
dp[i][j] = Math.max(dp[i - 1 ][j], dp[i - 1 ][j - w[i - 1 ]] + w[i - 1 ]);
} else {
dp[i][j] = dp[i - 1 ][j];
}
}
}
return dp;
}
public static void main(String[] args) {
int [] w = { 3 , 8 , 9 };
int n = w.length;
int [] queries = { 11 , 10 , 4 };
int q = queries.length;
int ma = Integer.MIN_VALUE;
for ( int query : queries) {
ma = Math.max(ma, query);
}
int [][] dp = findMax(w, n, ma);
for ( int i = 0 ; i < q; i++) {
System.out.println(dp[n][queries[i]]);
}
}
}
|
Python3
import sys
def findMax(w, n, c):
dp = [[ 0 for j in range (c + 1 )] for i in range (n + 1 )]
for i in range ( 1 , n + 1 ):
for j in range ( 1 , c + 1 ):
if w[i - 1 ] < = j:
dp[i][j] = max (dp[i - 1 ][j], dp[i - 1 ]
[j - w[i - 1 ]] + w[i - 1 ])
else :
dp[i][j] = dp[i - 1 ][j]
return dp
if __name__ = = '__main__' :
w = [ 3 , 8 , 9 ]
n = len (w)
queries = [ 11 , 10 , 4 ]
q = len (queries)
ma = max (queries)
dp = findMax(w, n, ma)
for i in range (q):
print (dp[n][queries[i]])
|
C#
using System;
public class MaxSubsetSum
{
static int [,] findMax( int [] w, int n, int c)
{
int [,] dp = new int [n + 1, c + 1];
for ( int i = 1; i <= n; i++)
{
for ( int j = 1; j <= c; j++)
{
if (w[i - 1] <= j)
{
dp[i, j] = Math.Max(dp[i - 1, j], dp[i - 1, j - w[i - 1]] + w[i - 1]);
}
else
{
dp[i, j] = dp[i - 1, j];
}
}
}
return dp;
}
public static void Main( string [] args)
{
int [] w = { 3, 8, 9 };
int n = w.Length;
int [] queries = { 11, 10, 4 };
int q = queries.Length;
int ma = int .MinValue;
foreach ( int query in queries)
{
ma = Math.Max(ma, query);
}
int [,] dp = findMax(w, n, ma);
for ( int i = 0; i < q; i++)
{
Console.WriteLine(dp[n, queries[i]]);
}
}
}
|
Javascript
function findMax(w, n, c) {
let dp = new Array(n + 1).fill( null ).map(() => new Array(c + 1).fill(0));
for (let i = 1; i <= n; i++) {
for (let j = 1; j <= c; j++) {
if (w[i - 1] <= j) {
dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - w[i - 1]] + w[i - 1]);
} else {
dp[i][j] = dp[i - 1][j];
}
}
}
return dp;
}
const w = [3, 8, 9];
const n = w.length;
const queries = [11, 10, 4];
const q = queries.length;
const ma = Math.max(...queries);
const dp = findMax(w, n, ma);
for (let i = 0; i < q; i++) {
console.log(dp[n][queries[i]]);
}
|
Time complexity: O(n*c)
Auxiliary Space: O(n*C)
Last Updated :
02 Oct, 2023
Like Article
Save Article
Share your thoughts in the comments
Please Login to comment...