Maximum sum of values of N items in 0-1 Knapsack by reducing weight of at most K items in half

Given weights and values of N items and the capacity W of the knapsack. Also given that the weight of at most K items can be changed to half of its original weight. The task is to find the maximum sum of values of N items that can be obtained such that the sum of weights of items in knapsack does not exceed the given capacity W.
Examples:
Input: W = 4, K = 1, value = [17, 20, 10, 15], weight = [4, 2, 7, 5]Output: 37
Explanation: Change the weight of at most K items to half of the weight in a optimal way to get maximum value. Decrease the weight of first item to half and add second item weight the resultant sum of value is 37 which is maximumInput: W = 8, K = 2, value = [17, 20, 10, 15], weight = [4, 2, 7, 5]Â
Output: 52
Explanation: Change the weight of the last item and first item and the add the weight the of the 2nd item, The total sum value of item will be 52.
Approach: Given problem is the variation of the 0 1 knapsack  problem. Flag indicates number of items whose weight has been reduced to half. At every recursive call maximum of following cases is calculated and returned:
- Base case: If the index exceeds the length of values then return zero
- If flag is equal to K, maximum of 2 cases is considered:
- Include item with full weight if item’s weight does not exceed remaining weight
- Skip the item
- If flag is less than K, maximum of 3 cases is considered:
- Include item with full weight if item’s weight does not exceed remaining weight
- Include item with half weight if item’s  half weight does not exceed remaining weight
- Skip the item
C++
// C++ Program to implement// the above approach#include <bits/stdc++.h>using namespace std;// Function to find the maximum valueÂ
int maximum(int value[], int weight[], int weight1,            int flag, int K, int index, int val_len){Â
    // base condition    if (index >= val_len) {Â
        return 0;    }Â
    // K elements already reduced    // to half of their weight    if (flag == K) {Â
        // Dont include item        int skip = maximum(value, weight, weight1, flag, K,                           index + 1, val_len);Â
        int full = 0;Â
        // If weight of the item is        // less than or equal to the        // remaining weight then include        // the item        if (weight[index] <= weight1) {Â
            full = value[index]                   + maximum(value, weight,                             weight1 - weight[index], flag,                             K, index + 1, val_len);        }Â
        // Return the maximum of        // both cases        return max(full, skip);    }Â
    // If the weight reduction to half    // is possible    else {Â
        // Skip the item        int skip = maximum(value, weight, weight1, flag, K,                           index + 1, val_len);Â
        int full = 0;        int half = 0;Â
        // Include item with full weight        // if weight of the item is less        // than the remaining weight        if (weight[index] <= weight1) {Â
            full = value[index]                   + maximum(value, weight,                             weight1 - weight[index], flag,                             K, index + 1, val_len);        }Â
        // Include item with half weight        // if half weight of the item is        // less than the remaining weight        if (weight[index] / 2 <= weight1) {Â
            half = value[index]                   + maximum(value, weight,                             weight1 - weight[index] / 2,                             flag + 1, K, index + 1,                             val_len);        }Â
        // Return the maximum of all 3 cases        return max(full, max(skip, half));    }}int main(){Â
    int value[] = { 17, 20, 10, 15 };    int weight[] = { 4, 2, 7, 5 };    int K = 1;    int W = 4;    int val_len = sizeof(value) / sizeof(value[0]);    cout << (maximum(value, weight, W, 0, K, 0, val_len));Â
    return 0;}Â
// This code is contributed by Potta Lokesh |
Java
// Java implementation for the above approachimport java.io.*;import java.util.*;Â
class GFG {Â
    // Function to find the maximum value    static int maximum(int value[], int weight[],                       int weight1, int flag, int K,                       int index)    {Â
        // base condition        if (index >= value.length) {Â
            return 0;        }Â
        // K elements already reduced        // to half of their weight        if (flag == K) {Â
            // Dont include item            int skip = maximum(value, weight, weight1, flag,                               K, index + 1);Â
            int full = 0;Â
            // If weight of the item is            // less than or equal to the            // remaining weight then include            // the item            if (weight[index] <= weight1) {Â
                full = value[index]                       + maximum(value, weight,                                 weight1 - weight[index],                                 flag, K, index + 1);            }Â
            // Return the maximum of            // both cases            return Math.max(full, skip);        }Â
        // If the weight reduction to half        // is possible        else {Â
            // Skip the item            int skip = maximum(value, weight, weight1, flag,                               K, index + 1);Â
            int full = 0;            int half = 0;Â
            // Include item with full weight            // if weight of the item is less            // than the remaining weight            if (weight[index] <= weight1) {Â
                full = value[index]                       + maximum(value, weight,                                 weight1 - weight[index],                                 flag, K, index + 1);            }Â
            // Include item with half weight            // if half weight of the item is            // less than the remaining weight            if (weight[index] / 2 <= weight1) {Â
                half                    = value[index]                      + maximum(value, weight,                                weight1 - weight[index] / 2,                                flag, K, index + 1);            }Â
            // Return the maximum of all 3 cases            return Math.max(full, Math.max(skip, half));        }    }Â
    public static void main(String[] args) throws Exception    {Â
        int value[] = { 17, 20, 10, 15 };        int weight[] = { 4, 2, 7, 5 };        int K = 1;        int W = 4;        System.out.println(            maximum(value, weight, W, 0, K, 0));    }} |
Python3
# Python program for the above approachÂ
# Function to find the maximum valueÂ
Â
def maximum(value,            weight, weight1,            flag, K, index, val_len):Â
    # base condition    if (index >= val_len):Â
        return 0Â
    # K elements already reduced    # to half of their weight    if (flag == K):Â
        # Dont include item        skip = maximum(value,                       weight, weight1,                       flag, K, index + 1, val_len)Â
        full = 0Â
        # If weight of the item is        # less than or equal to the        # remaining weight then include        # the item        if (weight[index] <= weight1):Â
            full = value[index] + maximum(                value, weight,                weight1 - weight[index], flag,                K, index + 1, val_len)Â
        # Return the maximum of        # both cases        return max(full, skip)Â
    # If the weight reduction to half    # is possible    else:Â
        # Skip the item        skip = maximum(            value, weight,            weight1, flag,            K, index + 1, val_len)Â
        full = 0        half = 0Â
        # Include item with full weight        # if weight of the item is less        # than the remaining weight        if (weight[index] <= weight1):Â
            full = value[index] + maximum(                value, weight,                weight1 - weight[index],                flag, K, index + 1, val_len)Â
        # Include item with half weight        # if half weight of the item is        # less than the remaining weight        if (weight[index] / 2 <= weight1):Â
            half = value[index] + maximum(                value, weight,                weight1 - weight[index] / 2,                flag, K, index + 1, val_len)Â
        # Return the maximum of all 3 cases        return max(full,                   max(skip, half))Â
Â
# Driver CodeÂ
value = [17, 20, 10, 15]weight = [4, 2, 7, 5]K = 1W = 4val_len = len(value)print(maximum(value, weight, W,              0, K, 0, val_len))Â
# This code is contributed by sanjoy_62. |
C#
// C# implementation for the above approachusing System;Â
public class GFG {Â
    // Function to find the maximum value    static int maximum(int[] value, int[] weight,                       int weight1, int flag, int K,                       int index)    {Â
        // base condition        if (index >= value.Length) {Â
            return 0;        }Â
        // K elements already reduced        // to half of their weight        if (flag == K) {Â
            // Dont include item            int skip = maximum(value, weight, weight1, flag,                               K, index + 1);Â
            int full = 0;Â
            // If weight of the item is            // less than or equal to the            // remaining weight then include            // the item            if (weight[index] <= weight1) {Â
                full = value[index]                       + maximum(value, weight,                                 weight1 - weight[index],                                 flag, K, index + 1);            }Â
            // Return the maximum of            // both cases            return Math.Max(full, skip);        }Â
        // If the weight reduction to half        // is possible        else {Â
            // Skip the item            int skip = maximum(value, weight, weight1, flag,                               K, index + 1);Â
            int full = 0;            int half = 0;Â
            // Include item with full weight            // if weight of the item is less            // than the remaining weight            if (weight[index] <= weight1) {Â
                full = value[index]                       + maximum(value, weight,                                 weight1 - weight[index],                                 flag, K, index + 1);            }Â
            // Include item with half weight            // if half weight of the item is            // less than the remaining weight            if (weight[index] / 2 <= weight1) {Â
                half                    = value[index]                      + maximum(value, weight,                                weight1 - weight[index] / 2,                                flag, K, index + 1);            }Â
            // Return the maximum of all 3 cases            return Math.Max(full, Math.Max(skip, half));        }    }Â
    // Driver code    public static void Main(String[] args)    {Â
        int[] value = { 17, 20, 10, 15 };        int[] weight = { 4, 2, 7, 5 };        int K = 1;        int W = 4;        Console.WriteLine(            maximum(value, weight, W, 0, K, 0));    }}Â
// This code is contributed by shikhasingrajput |
Javascript
<script>// javascript implementation for the above approach  // Function to find the maximum value    function maximum(value,                       weight , weight1,                       flag , K , index)    {Â
        // base condition        if (index >= value.length) {Â
            return 0;        }Â
        // K elements already reduced        // to half of their weight        if (flag == K) {Â
            // Dont include item            var skip = maximum(value,                               weight, weight1,                               flag, K, index + 1);Â
            var full = 0;Â
            // If weight of the item is            // less than or equal to the            // remaining weight then include            // the item            if (weight[index] <= weight1) {Â
                full = value[index]                       + maximum(                             value, weight,                             weight1 - weight[index], flag,                             K, index + 1);            }Â
            // Return the maximum of            // both cases            return Math.max(full, skip);        }Â
        // If the weight reduction to half        // is possible        else {Â
            // Skip the item            var skip = maximum(                value, weight,                weight1, flag,                K, index + 1);Â
            var full = 0;            var half = 0;Â
            // Include item with full weight            // if weight of the item is less            // than the remaining weight            if (weight[index] <= weight1) {Â
                full = value[index]                       + maximum(                             value, weight,                             weight1 - weight[index],                             flag, K, index + 1);            }Â
            // Include item with half weight            // if half weight of the item is            // less than the remaining weight            if (weight[index] / 2 <= weight1) {Â
                half = value[index]                       + maximum(                             value, weight,                             weight1 - weight[index] / 2,                             flag, K, index + 1);            }Â
            // Return the maximum of all 3 cases            return Math.max(full,                            Math.max(skip, half));        }    }Â
// Driver codevar value = [ 17, 20, 10, 15 ];var weight = [ 4, 2, 7, 5 ];var K = 1;var W = 4;document.write(    maximum(value, weight, W,            0, K, 0));Â
// This code is contributed by Princi Singh </script> |
37
Time Complexity: O(3^N)
Auxiliary Space: O(N)
Given problem is the variation of the 0-1 knapsack  problem. In traditional 0-1 Knapsack problem, we only have to choices: skip the i-th item or take it.Â
However, in this case we will have 3 choices as mentioned in the recursive approach.
Efficient Approach (Dynamic Programming):
In Dynamic programming, we will work considering the same cases as above. We shall consider a 3D DP table where the state DP[i][j][k] will denote the maximum value we can obtain if we are considering values from 1 to i-th, weight of the knapsack is j and we can half the weight of at most k values. Basically, we are adding one extra state, the number of weights that can be halved in a traditional 2-D 01 knapsack DP matrix.
Now, three possibilities can take place:
- Include item with full weight if the item’s weight does not exceed the remaining weight
- Include the item with half weight if the item’s  half weight does not exceed the remaining weight
- Skip the item
Now we have to take the maximum of these three possibilities. If we do not take the i-th weight then dp[i][j][k] would remain equal to dp[i – 1][j][k], just llike traditional knapsack. If we include item with half weight then dp[i][j][k] would be equal to dp[i – 1][j – wt[i] / 2][k – 1] + val[i] as after including i-th value our remaining knapsack capacity would be j – wt[i] / 2 and our number of half operations would increase by 1. Similarly, if we include item with full weight then dp[i][j][k] would be equal to dp[i – 1][j – wt[i]][k] + val[i] as knapsack capacity in this case would reduce to j – wt[i].
We simply take the maximum of all three choices.
Â
Below is the code implementation of above approach:
C++
#include <iostream>#include <vector>#include <cstring>using namespace std;int getMaximumNutrition(int W, vector<int> value, vector<int> weight, int x) {    int n=value.size();    int dp[n + 1][W + 1][x + 1];  /*  dp[i][j][k] denotes the maximum value that we can obtain if we are considering first i   elements of array, our capacity is j and we can use only k half operations  */    memset(dp, 0, sizeof(dp));    for(int i = 1;i <= n; i++)    {        for(int j = 1;j <= W; j++)        {            int lim = x;            if(lim > i)            {                lim = i;            }            for(int k = 0;k <= lim; k++)            {                dp[i][j][k] = max(dp[i - 1][j][k], dp[i][j][k]);//skip                int val = j - (weight[i - 1] / 2);                if(val >= 0 && k > 0)//ensure that j-weight[i-1]/2 and k-1 don't become -ve                {                    dp[i][j][k] = max(dp[i - 1][val][k - 1]+value[i - 1], dp[i][j][k]);                  //take item applying half operation                }                val = j - weight[i - 1];                if(val >= 0)//ensure that j-weight[i-1] doesn't become -ve                {                    dp[i][j][k] = max(dp[i - 1][val][k] + value[i - 1], dp[i][j][k]);                  //take item without applying half operation                }            }        }    }    return dp[n][W][x];}int main() {    vector<int> value = {17, 20, 10, 15};    vector<int> weight = {4, 2, 7, 5};    int x = 1;    int W = 4;    cout << getMaximumNutrition(W, value, weight, x);    return 0;} |
Java
import java.util.*;public class Main {Â
  static int getMaximumNutrition(int W, int[] value,                                 int[] weight, int x)  {    int n = value.length;    int[][][] dp = new int[n + 1][W + 1][x + 1];    /*        dp[i][j][k] denotes the maximum value that we can        obtain if we are considering first i elements of        array, our capacity is j and we can use only k half        operations        */Â
    for (int i = 1; i <= n; i++) {      for (int j = 1; j <= W; j++) {        int lim = x;        if (lim > i) {          lim = i;        }        for (int k = 0; k <= lim; k++) {          dp[i][j][k]            = Math.max(dp[i - 1][j][k],                       dp[i][j][k]); // skip          int val = j - (weight[i - 1] / 2);          if (val >= 0              && k > 0) // ensure that            // j-weight[i-1]/2 and k-1            // don't become -ve          {            dp[i][j][k]              = Math.max(dp[i - 1][val][k - 1]                         + value[i - 1],                         dp[i][j][k]);            // take item applying half operation          }          val = j - weight[i - 1];          if (val              >= 0) // ensure that j-weight[i-1]            // doesn't become -ve          {            dp[i][j][k]              = Math.max(dp[i - 1][val][k]                         + value[i - 1],                         dp[i][j][k]);            // take item without applying half            // operation          }        }      }    }    return dp[n][W][x];  }  public static void main(String[] args)  {    int[] value = { 17, 20, 10, 15 };    int[] weight = { 4, 2, 7, 5 };    int x = 1;    int W = 4;    System.out.println(      getMaximumNutrition(W, value, weight, x));  }}Â
// This code is contributed by garg28harsh. |
C#
using System;class GFG {  static int getMaximumNutrition(int W, int[] value,                                 int[] weight, int x)  {    int n = value.Length;    int[, , ] dp = new int[n + 1, W + 1, x + 1];    /*        dp[i][j][k] denotes the maximum value that we can        obtain if we are considering first i elements of        array, our capacity is j and we can use only k half        operations        */Â
    for (int i = 1; i <= n; i++) {      for (int j = 1; j <= W; j++) {        int lim = x;        if (lim > i) {          lim = i;        }        for (int k = 0; k <= lim; k++) {          dp[i, j, k]            = Math.Max(dp[i - 1, j, k],                       dp[i, j, k]); // skip          int val = j - (weight[i - 1] / 2);          if (val >= 0              && k > 0) // ensure that            // j-weight[i-1]/2 and k-1            // don't become -ve          {            dp[i, j, k]              = Math.Max(dp[i - 1, val, k - 1]                         + value[i - 1],                         dp[i, j, k]);            // take item applying half operation          }          val = j - weight[i - 1];          if (val              >= 0) // ensure that j-weight[i-1]            // doesn't become -ve          {            dp[i, j, k]              = Math.Max(dp[i - 1, val, k]                         + value[i - 1],                         dp[i, j, k]);            // take item without applying half            // operation          }        }      }    }    return dp[n, W, x];  }  static void Main()  {    int[] val = { 17, 20, 10, 15 };    int[] weight = { 4, 2, 7, 5 };    int x = 1;    int W = 4;    Console.Write(      getMaximumNutrition(W, val, weight, x));  }}Â
// This code is contributed by garg28harsh. |
Javascript
function getMaximumNutrition(W, value, weight, x) {    let n=value.length;    /*  dp[i][j][k] denotes the maximum value that we can obtain if we are considering first i   elements of array, our capacity is j and we can use only k half operations  */    let dp = new Array(n+1);    for(let i = 0; i < n + 1; i++)    {        dp[i] = new Array(W+1);        for(let j = 0; j < W + 1; j++)        {            dp[i][j] = new Array(x+1);            for(let k = 0; k < x + 1; k++)            {                dp[i][j][k] = 0;            }        }    }       for(let i = 1;i <= n; i++)    {        for(let j = 1;j <= W; j++)        {            let lim = x;            if(lim > i)            {                lim = i;            }            for(let k = 0;k <= lim; k++)            {                dp[i][j][k] = Math.max(dp[i - 1][j][k], dp[i][j][k]);//skip                let val = j - Math.round(weight[i - 1] / 2);                if(val >= 0 && k > 0)//ensure that j-weight[i-1]/2 and k-1 don't become -ve                {                    dp[i][j][k] = Math.max(dp[i - 1][val][k - 1]+value[i - 1], dp[i][j][k]);                  //take item applying half operation                }                val = j - weight[i - 1];                if(val >= 0)//ensure that j-weight[i-1] doesn't become -ve                {                    dp[i][j][k] = Math.max(dp[i - 1][val][k] + value[i - 1], dp[i][j][k]);                  //take item without applying half operation                }            }        }    }    return dp[n][W][x];}Â
    let value = [17, 20, 10, 15];    let weight = [4, 2, 7, 5];    let x = 1;    let W = 4;    console.log(getMaximumNutrition(W, value, weight, x));     // This code is contributed by garg28harsh. |
Python3
# Python3 code for the above approach:Â
from typing import List, TupleÂ
def getMaximumNutrition(W: int, value: List[int], weight: List[int], x: int) -> int:    n = len(value)    dp = [[[0 for _ in range(x+1)] for _ in range(W+1)] for _ in range(n+1)]    for i in range(1, n+1):        for j in range(1, W+1):            lim = min(x, i)            for k in range(lim+1):                dp[i][j][k] = max(dp[i-1][j][k], dp[i][j][k]) #skip                val = j - (weight[i-1] // 2)                if val >= 0 and k > 0: #ensure that j-weight[i-1]/2 and k-1 don't become negative                    dp[i][j][k] = max(dp[i-1][val][k-1] + value[i-1], dp[i][j][k]) # take item applying half operation                val = j - weight[i-1]                if val >= 0: #ensure that j-weight[i-1] doesn't become negative                    dp[i][j][k] = max(dp[i-1][val][k] + value[i-1], dp[i][j][k]) # take item without applying half operation    return dp[n][W][x]Â
if __name__ == "__main__":Â Â Â Â value = [17, 20, 10, 15]Â Â Â Â weight = [4, 2, 7, 5]Â Â Â Â x = 1Â Â Â Â W = 4Â Â Â Â print(getMaximumNutrition(W, value, weight, x)) |
37
Time Complexity: O(n*W*K)
Auxiliary Space: O(n*W*K)
Note that space complexity can be further reduced to O(W*2*2) as for computing some dp[i][j][k] we only need to know values at current and previous i-th and k-th state. Time complexity will remain the same.
Ready to dive in? Explore our Free Demo Content and join our DSA course, trusted by over 100,000 zambiatek!



