Facebook Pixel

0/1 Knapsack Practice Problem

Let's apply the 0/1 knapsack pattern with a practical example.

Given n items where item i has weight weights[i] and value values[i], find the maximum total value achievable without exceeding capacity max_weight. Each item can be selected at most once.

Input

  • weights: an array of integers that denote the weights of objects
  • values: an array of integers that denote the values of objects
  • max_weight: the maximum weight capacity of the knapsack

Output

the maximum value in the knapsack

Examples

Example 1:

Input:

weights = [3, 4, 7]
values = [4, 5, 8]
max_weight = 7

Output: 9

Explanation:

We have a knapsack of max limit 7 with 3 objects of weight-value pairs of [3,4], [4,5], [7,8], then the maximal value we can achieve is using the first 2 objects to obtain value 4 + 5 = 9.

The other possibilities would all be only 1 object in our knapsack, which would only yield values 4, 5, and 9.

Try it yourself

Solution

Approach

This is a direct application of the 0/1 knapsack pattern. The state dp[i][j] represents the maximum value using the first i items with capacity j. For each item, we choose between skipping it or including it:

dp[i][j] = max(dp[i-1][j], dp[i-1][j - weight] + value)

The decision tree below shows all possibilities. Each left branch represents taking an item, each right branch represents skipping it:

The path yielding value 9 (taking items with weights 3 and 4) is optimal.

Brute Force

A recursive approach tries all 2^n subsets:

1# helper function that returns the maximum value when considering
2# the first n items and remaining available weight remaining_weight
3def knapsack_helper(weights: list[int], values: list[int], remaining_weight: int, n: int) -> int:
4    # base case: if there are no items or no available weight in the knapsack to use, the maximum value is 0
5    if n == 0 or remaining_weight == 0:
6        return 0
7    # if the weight of the current item exceeds the available weight,
8    # skip the current item and process the next one
9    if weights[n - 1] > remaining_weight:
10        return knapsack_helper(weights, values, remaining_weight, n - 1)
11    # recurrence relation: choose the maximum of two possibilities:
12    #   (1) pick up the current item: current value + maximum value with the rest of the items
13    #   (2) give up the current item: maximum value with the rest of the items
14    return max(
15        values[n - 1] + knapsack_helper(weights, values, remaining_weight - weights[n - 1], n - 1),
16        knapsack_helper(weights, values, remaining_weight, n - 1),
17    )
18
19def knapsack(weights: list[int], values: list[int], max_weight: int) -> int:
20    n = len(weights)
21    return knapsack_helper(weights, values, max_weight, n)
22
23if __name__ == "__main__":
24    weights = [int(x) for x in input().split()]
25    values = [int(x) for x in input().split()]
26    max_weight = int(input())
27    res = knapsack(weights, values, max_weight)
28    print(res)
29
1import java.util.Arrays;
2import java.util.List;
3import java.util.Scanner;
4import java.util.stream.Collectors;
5
6class Solution {
7    // helper function that returns the maximum value when considering
8    // the first n items and remaining available weight remainingWeight
9    public static int knapsackHelper(List<Integer> weights, List<Integer> values, int remainingWeight, int n) {
10        // base case: if there are no items or no available weight in the knapsack to use, the maximum value is 0
11        if (n == 0 || remainingWeight == 0) {
12            return 0;
13        }
14        // if the weight of the current item exceeds the available weight,
15        // skip the current item and process the next one
16        if (weights.get(n - 1) > remainingWeight) {
17            return knapsackHelper(weights, values, remainingWeight, n - 1);
18        }
19        // recurrence relation: choose the maximum of two possibilities:
20        //   (1) pick up the current item: current value + maximum value with the rest of the items
21        //   (2) give up the current item: maximum value with the rest of the items
22        return Math.max(
23            values.get(n - 1) + knapsackHelper(weights, values, remainingWeight - weights.get(n - 1), n - 1),
24            knapsackHelper(weights, values, remainingWeight, n - 1));
25    }
26
27    public static int knapsack(List<Integer> weights, List<Integer> values, int maxWeight) {
28        int n = weights.size();
29        return knapsackHelper(weights, values, maxWeight, n);
30    }
31
32    public static List<String> splitWords(String s) {
33        return s.isEmpty() ? List.of() : Arrays.asList(s.split(" "));
34    }
35
36    public static void main(String[] args) {
37        Scanner scanner = new Scanner(System.in);
38        List<Integer> weights = splitWords(scanner.nextLine()).stream().map(Integer::parseInt).collect(Collectors.toList());
39        List<Integer> values = splitWords(scanner.nextLine()).stream().map(Integer::parseInt).collect(Collectors.toList());
40        int maxWeight = Integer.parseInt(scanner.nextLine());
41        scanner.close();
42        int res = knapsack(weights, values, maxWeight);
43        System.out.println(res);
44    }
45}
46
1"use strict";
2
3// helper function that returns the maximum value when considering
4// the first n items and remaining available weight remainingWeight
5function knapsackHelper(weights, values, remainingWeight, n) {
6    // base case: if there are no items or no available weight in the knapsack to use, the maximum value is 0
7    if (n === 0 || remainingWeight === 0) {
8        return 0;
9    }
10    // if the weight of the current item exceeds the available weight,
11    // skip the current item and process the next one
12    if (weights[n - 1] > remainingWeight) {
13        return knapsackHelper(weights, values, remainingWeight, n - 1);
14    }
15    // recurrence relation: choose the maximum of two possibilities:
16    //   (1) pick up the current item: current value + maximum value with the rest of the items
17    //   (2) give up the current item: maximum value with the rest of the items
18    return Math.max(
19        values[n - 1] + knapsackHelper(weights, values, remainingWeight - weights[n - 1], n - 1),
20        knapsackHelper(weights, values, remainingWeight, n - 1),
21    );
22}
23function knapsack(weights, values, maxWeight) {
24    const n = weights.length;
25    return knapsackHelper(weights, values, maxWeight, n);
26}
27
28function splitWords(s) {
29    return s === "" ? [] : s.split(" ");
30}
31
32function* main() {
33    const weights = splitWords(yield).map((v) => parseInt(v));
34    const values = splitWords(yield).map((v) => parseInt(v));
35    const maxWeight = parseInt(yield);
36    const res = knapsack(weights, values, maxWeight);
37    console.log(res);
38}
39
40class EOFError extends Error {}
41{
42    const gen = main();
43    const next = (line) => gen.next(line).done && process.exit();
44    let buf = "";
45    next();
46    process.stdin.setEncoding("utf8");
47    process.stdin.on("data", (data) => {
48        const lines = (buf + data).split("\n");
49        buf = lines.pop();
50        lines.forEach(next);
51    });
52    process.stdin.on("end", () => {
53        buf && next(buf);
54        gen.throw(new EOFError());
55    });
56}
57
1function knapsackHelper(weights: number[], values: number[], remainingWeight: number, n: number): number {
2    if (n === 0 || remainingWeight === 0) {
3        return 0;
4    }
5    if (weights[n - 1] > remainingWeight) {
6        return knapsackHelper(weights, values, remainingWeight, n - 1);
7    }
8    return Math.max(
9        values[n - 1] + knapsackHelper(weights, values, remainingWeight - weights[n - 1], n - 1),
10        knapsackHelper(weights, values, remainingWeight, n - 1),
11    );
12}
13function knapsack(weights: number[], values: number[], maxWeight: number): number {
14    const n = weights.length;
15    return knapsackHelper(weights, values, maxWeight, n);
16}
17
18function splitWords(s: string): string[] {
19    return s === "" ? [] : s.split(" ");
20}
21
22function* main() {
23    const weights = splitWords(yield).map((v) => parseInt(v));
24    const values = splitWords(yield).map((v) => parseInt(v));
25    const maxWeight = parseInt(yield);
26    const res = knapsack(weights, values, maxWeight);
27    console.log(res);
28}
29
30class EOFError extends Error {}
31{
32    const gen = main();
33    const next = (line?: string) => gen.next(line ?? "").done && process.exit();
34    let buf = "";
35    next();
36    process.stdin.setEncoding("utf8");
37    process.stdin.on("data", (data) => {
38        const lines = (buf + data).split("\n");
39        buf = lines.pop() ?? "";
40        lines.forEach(next);
41    });
42    process.stdin.on("end", () => {
43        buf && next(buf);
44        gen.throw(new EOFError());
45    });
46}
47
1#include <algorithm>
2#include <iostream>
3#include <iterator>
4#include <limits>
5#include <sstream>
6#include <string>
7#include <vector>
8
9// helper function that returns the maximum value when considering
10// the first n items and remaining available weight remaining_weight
11int knapsackHelper(std::vector<int>& weights, std::vector<int>& values, int remaining_weight, int n) {
12    // base case: if there are no items or no available weight in the knapsack to use, the maximum value is 0
13    if (n == 0 || remaining_weight == 0) {
14        return 0;
15    }
16    // if the weight of the current item exceeds the available weight,
17    // skip the current item and process the next one
18    if (weights[n - 1] > remaining_weight) {
19        return knapsackHelper(weights, values, remaining_weight, n - 1);
20    }
21    // recurrence relation: choose the maximum of two possibilities:
22    //   (1) pick up the current item: current value + maximum value with the rest of the items
23    //   (2) give up the current item: maximum value with the rest of the items
24    return std::max(
25        values[n - 1] + knapsackHelper(weights, values, remaining_weight - weights[n - 1], n - 1),
26        knapsackHelper(weights, values, remaining_weight, n - 1));
27}
28int knapsack(std::vector<int>& weights, std::vector<int>& values, int max_weight) {
29    int n = weights.size();
30    return knapsackHelper(weights, values, max_weight, n);
31}
32
33template<typename T>
34std::vector<T> get_words() {
35    std::string line;
36    std::getline(std::cin, line);
37    std::istringstream ss{line};
38    ss >> std::boolalpha;
39    std::vector<T> v;
40    std::copy(std::istream_iterator<T>{ss}, std::istream_iterator<T>{}, std::back_inserter(v));
41    return v;
42}
43
44void ignore_line() {
45    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
46}
47
48int main() {
49    std::vector<int> weights = get_words<int>();
50    std::vector<int> values = get_words<int>();
51    int max_weight;
52    std::cin >> max_weight;
53    ignore_line();
54    int res = knapsack(weights, values, max_weight);
55    std::cout << res << '\n';
56}
57

Memoization

The brute force has overlapping subproblems. Adding memoization avoids recomputation by storing results in dp[n][remaining_weight]:

1def knapsack_helper(
2    weights: list[int],
3    values: list[int],
4    memo: list[list[int]],
5    remaining_weight: int,
6    n: int,
7) -> int:
8    if n == 0 or remaining_weight == 0:
9        return 0
10    if memo[n][remaining_weight] != -1:
11        return memo[n][remaining_weight]
12    res = 0
13    if weights[n - 1] > remaining_weight:
14        res = knapsack_helper(weights, values, memo, remaining_weight, n - 1)
15    else:
16        res = max(
17            values[n - 1] + knapsack_helper(weights, values, memo, remaining_weight - weights[n - 1], n - 1),
18            knapsack_helper(weights, values, memo, remaining_weight, n - 1),
19        )
20    memo[n][remaining_weight] = res
21    return res
22
23def knapsack(weights: list[int], values: list[int], max_weight: int) -> int:
24    n = len(weights)
25    memo = [[-1 for i in range(max_weight + 1)] for j in range(n + 1)]
26    return knapsack_helper(weights, values, memo, max_weight, n)
27
28if __name__ == "__main__":
29    weights = [int(x) for x in input().split()]
30    values = [int(x) for x in input().split()]
31    max_weight = int(input())
32    res = knapsack(weights, values, max_weight)
33    print(res)
34
1import java.util.Arrays;
2import java.util.List;
3import java.util.Scanner;
4import java.util.stream.Collectors;
5
6class Solution {
7    public static int knapsackHelper(List<Integer> weights, List<Integer> values, int[][] memo, int remainingWeight, int n) {
8        if (n == 0 || remainingWeight == 0) {
9            return 0;
10        }
11        if (memo[n][remainingWeight] != -1) {
12            return memo[n][remainingWeight];
13        }
14        int res;
15        if (weights.get(n - 1) > remainingWeight) {
16            res = knapsackHelper(weights, values, memo, remainingWeight, n - 1);
17        } else {
18            res = Math.max(
19                values.get(n - 1) + knapsackHelper(weights, values, memo, remainingWeight - weights.get(n - 1), n - 1),
20                knapsackHelper(weights, values, memo, remainingWeight, n - 1));
21        }
22        return memo[n][remainingWeight] = res;
23    }
24
25    public static int knapsack(List<Integer> weights, List<Integer> values, int maxWeight) {
26        int n = weights.size();
27        int[][] memo = new int[n + 1][maxWeight + 1];
28        for (int i = 0; i < n + 1; i++) {
29            Arrays.fill(memo[i], -1);
30        }
31        return knapsackHelper(weights, values, memo, maxWeight, n);
32    }
33
34    public static List<String> splitWords(String s) {
35        return s.isEmpty() ? List.of() : Arrays.asList(s.split(" "));
36    }
37
38    public static void main(String[] args) {
39        Scanner scanner = new Scanner(System.in);
40        List<Integer> weights = splitWords(scanner.nextLine()).stream().map(Integer::parseInt).collect(Collectors.toList());
41        List<Integer> values = splitWords(scanner.nextLine()).stream().map(Integer::parseInt).collect(Collectors.toList());
42        int maxWeight = Integer.parseInt(scanner.nextLine());
43        scanner.close();
44        int res = knapsack(weights, values, maxWeight);
45        System.out.println(res);
46    }
47}
48
1"use strict";
2
3function knapsackHelper(weights, values, memo, remainingWeight, n) {
4    if (n === 0 || remainingWeight === 0) {
5        return 0;
6    }
7    if (memo[n][remainingWeight] !== -1) {
8        return memo[n][remainingWeight];
9    }
10    let res;
11    if (weights[n - 1] > remainingWeight) {
12        res = knapsackHelper(weights, values, memo, remainingWeight, n - 1);
13    } else {
14        res = Math.max(
15            values[n - 1] + knapsackHelper(weights, values, memo, remainingWeight - weights[n - 1], n - 1),
16            knapsackHelper(weights, values, memo, remainingWeight, n - 1),
17        );
18    }
19    memo[n][remainingWeight] = res;
20    return res;
21}
22function knapsack(weights, values, maxWeight) {
23    const n = weights.length;
24    const memo = new Array(n + 1).fill().map(() => new Array(maxWeight + 1).fill(-1));
25    return knapsackHelper(weights, values, memo, maxWeight, n);
26}
27
28function splitWords(s) {
29    return s === "" ? [] : s.split(" ");
30}
31
32function* main() {
33    const weights = splitWords(yield).map((v) => parseInt(v));
34    const values = splitWords(yield).map((v) => parseInt(v));
35    const maxWeight = parseInt(yield);
36    const res = knapsack(weights, values, maxWeight);
37    console.log(res);
38}
39
40class EOFError extends Error {}
41{
42    const gen = main();
43    const next = (line) => gen.next(line).done && process.exit();
44    let buf = "";
45    next();
46    process.stdin.setEncoding("utf8");
47    process.stdin.on("data", (data) => {
48        const lines = (buf + data).split("\n");
49        buf = lines.pop();
50        lines.forEach(next);
51    });
52    process.stdin.on("end", () => {
53        buf && next(buf);
54        gen.throw(new EOFError());
55    });
56}
57
1function knapsackHelper(weights: number[], values: number[], memo: number[][], remainingWeight: number, n: number): number {
2    if (n === 0 || remainingWeight === 0) {
3        return 0;
4    }
5    if (memo[n][remainingWeight] !== -1) {
6        return memo[n][remainingWeight];
7    }
8    let res;
9    if (weights[n - 1] > remainingWeight) {
10        res = knapsackHelper(weights, values, memo, remainingWeight, n - 1);
11    } else {
12        res = Math.max(
13            values[n - 1] + knapsackHelper(weights, values, memo, remainingWeight - weights[n - 1], n - 1),
14            knapsackHelper(weights, values, memo, remainingWeight, n - 1),
15        );
16    }
17    memo[n][remainingWeight] = res;
18    return res;
19}
20function knapsack(weights: number[], values: number[], maxWeight: number): number {
21    const n = weights.length;
22    const memo = new Array(n + 1).fill(0).map(() => new Array(maxWeight + 1).fill(-1));
23    return knapsackHelper(weights, values, memo, maxWeight, n);
24}
25
26function splitWords(s: string): string[] {
27    return s === "" ? [] : s.split(" ");
28}
29
30function* main() {
31    const weights = splitWords(yield).map((v) => parseInt(v));
32    const values = splitWords(yield).map((v) => parseInt(v));
33    const maxWeight = parseInt(yield);
34    const res = knapsack(weights, values, maxWeight);
35    console.log(res);
36}
37
38class EOFError extends Error {}
39{
40    const gen = main();
41    const next = (line?: string) => gen.next(line ?? "").done && process.exit();
42    let buf = "";
43    next();
44    process.stdin.setEncoding("utf8");
45    process.stdin.on("data", (data) => {
46        const lines = (buf + data).split("\n");
47        buf = lines.pop() ?? "";
48        lines.forEach(next);
49    });
50    process.stdin.on("end", () => {
51        buf && next(buf);
52        gen.throw(new EOFError());
53    });
54}
55
1#include <algorithm>
2#include <iostream>
3#include <iterator>
4#include <limits>
5#include <sstream>
6#include <string>
7#include <vector>
8
9int knapsackHelper(std::vector<int>& weights, std::vector<int>& values, std::vector<std::vector<int>>& memo, int remaining_weight, int n) {
10    if (n == 0 || remaining_weight == 0) {
11        return 0;
12    }
13    if (memo[n][remaining_weight] != -1) {
14        return memo[n][remaining_weight];
15    }
16    int res;
17    if (weights[n - 1] > remaining_weight) {
18        res = knapsackHelper(weights, values, memo, remaining_weight, n - 1);
19    } else {
20        res = std::max(
21            values[n - 1] + knapsackHelper(weights, values, memo, remaining_weight - weights[n - 1], n - 1),
22            knapsackHelper(weights, values, memo, remaining_weight, n - 1));
23    }
24    return memo[n][remaining_weight] = res;
25}
26
27int knapsack(std::vector<int>& weights, std::vector<int>& values, int max_weight) {
28    int n = weights.size();
29    std::vector<std::vector<int>> memo(n + 1, std::vector<int>(max_weight + 1, -1));
30    return knapsackHelper(weights, values, memo, max_weight, n);
31}
32
33template<typename T>
34std::vector<T> get_words() {
35    std::string line;
36    std::getline(std::cin, line);
37    std::istringstream ss{line};
38    ss >> std::boolalpha;
39    std::vector<T> v;
40    std::copy(std::istream_iterator<T>{ss}, std::istream_iterator<T>{}, std::back_inserter(v));
41    return v;
42}
43
44void ignore_line() {
45    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
46}
47
48int main() {
49    std::vector<int> weights = get_words<int>();
50    std::vector<int> values = get_words<int>();
51    int max_weight;
52    std::cin >> max_weight;
53    ignore_line();
54    int res = knapsack(weights, values, max_weight);
55    std::cout << res << '\n';
56}
57

Time and space complexity: O(n × max_weight) for both, since we have that many states and each takes O(1) to compute.

Bottom-up DP

Converting to iterative form, we fill a 2D table row by row:

1def knapsack(weights: list[int], values: list[int], max_weight: int) -> int:
2    n = len(weights)
3    # 2D dp array, where max_value[i][j] is the maximum knapsack value when
4    # considering the first i items with a max weight capacity of j
5    max_value = [[0 for i in range(max_weight + 1)] for j in range(n + 1)]
6    # iterate through all items
7    for i in range(n + 1):
8        # and all possible available weights
9        for w in range(max_weight + 1):
10            if i == 0 or w == 0:
11                # if we consider no items or no weight, the max value is 0
12                max_value[i][w] = 0
13            elif w < weights[i - 1]:
14                # if the weight of the current item exceeds the max available weight,
15                # then the answer is the max value when considering the first i - 1 items
16                max_value[i][w] = max_value[i - 1][w]
17            else:
18                # otherwise, we choose the best option between either:
19                # picking up: item's value + max value when considering the rest of the items and a new weight
20                # giving up: similar to the condition above
21                max_value[i][w] = max(
22                    values[i - 1] + max_value[i - 1][w - weights[i - 1]],
23                    max_value[i - 1][w],
24                )
25    # the answer is the max value when considering all n items and available weight of max_weight
26    return max_value[n][max_weight]
27
28if __name__ == "__main__":
29    weights = [int(x) for x in input().split()]
30    values = [int(x) for x in input().split()]
31    max_weight = int(input())
32    res = knapsack(weights, values, max_weight)
33    print(res)
34
1import java.util.Arrays;
2import java.util.List;
3import java.util.Scanner;
4import java.util.stream.Collectors;
5
6class Solution {
7    public static int knapsack(List<Integer> weights, List<Integer> values, int remainingWeight) {
8        int n = weights.size();
9        // 2D dp array, where maxValue[i][j] is the maximum knapsack value when
10        // considering the first i items with a max weight capacity of j
11        int[][] maxValue = new int[n + 1][remainingWeight + 1];
12        // iterate through all items
13        for (int i = 0; i <= n; i++) {
14            // and all possible available weights
15            for (int w = 0; w <= remainingWeight; w++) {
16                if (i == 0 || w == 0) {
17                    // if we consider no items or no weight, the max value is 0
18                    maxValue[i][w] = 0;
19                } else if (w < weights.get(i - 1)) {
20                    // if the weight of the current item exceeds the max available weight,
21                    // then the answer is the max value when considering the first i - 1 items
22                    maxValue[i][w] = maxValue[i - 1][w];
23                } else {
24                    // otherwise, we choose the best option between either:
25                    // picking up: item's value + max value when considering the rest of the items and a new weight
26                    // giving up: similar to the condition above
27                    maxValue[i][w] = Math.max(
28                        values.get(i - 1) + maxValue[i - 1][w - weights.get(i - 1)],
29                        maxValue[i - 1][w]);
30                }
31            }
32        }
33        // the answer is the max value when considering all n items and available weight of max_weight
34        return maxValue[n][remainingWeight];
35    }
36
37    public static List<String> splitWords(String s) {
38        return s.isEmpty() ? List.of() : Arrays.asList(s.split(" "));
39    }
40
41    public static void main(String[] args) {
42        Scanner scanner = new Scanner(System.in);
43        List<Integer> weights = splitWords(scanner.nextLine()).stream().map(Integer::parseInt).collect(Collectors.toList());
44        List<Integer> values = splitWords(scanner.nextLine()).stream().map(Integer::parseInt).collect(Collectors.toList());
45        int maxWeight = Integer.parseInt(scanner.nextLine());
46        scanner.close();
47        int res = knapsack(weights, values, maxWeight);
48        System.out.println(res);
49    }
50}
51
1"use strict";
2
3function knapsack(weights, values, remainingWeight) {
4    const n = weights.length;
5    // 2D dp array, where maxValue[i][j] is the maximum knapsack value when
6    // considering the first i items with a max weight capacity of j
7    const maxValue = new Array(n + 1);
8    for (let i = 0; i <= n; i++) {
9        maxValue[i] = new Array(remainingWeight + 1).fill(0);
10    }
11    // iterate through all items
12    for (let i = 0; i <= n; i++) {
13        // and all possible available weights
14        for (let w = 0; w <= remainingWeight; w++) {
15            if (i === 0 || w === 0) {
16                // if we consider no items or no weight, the max value is 0
17                maxValue[i][w] = 0;
18            } else if (w < weights[i - 1]) {
19                // if the weight of the current item exceeds the max available weight,
20                // then the answer is the max value when considering the first i - 1 items
21                maxValue[i][w] = maxValue[i - 1][w];
22            } else {
23                // otherwise, we choose the best option between either:
24                // picking up: item's value + max value when considering the rest of the items and a new weight
25                // giving up: similar to the condition above
26                maxValue[i][w] = Math.max(
27                    values[i - 1] + maxValue[i - 1][w - weights[i - 1]],
28                    maxValue[i - 1][w],
29                );
30            }
31        }
32    }
33    // the answer is the max value when considering all n items and available weight of max_weight
34    return maxValue[n][remainingWeight];
35}
36
37function splitWords(s) {
38    return s === "" ? [] : s.split(" ");
39}
40
41function* main() {
42    const weights = splitWords(yield).map((v) => parseInt(v));
43    const values = splitWords(yield).map((v) => parseInt(v));
44    const maxWeight = parseInt(yield);
45    const res = knapsack(weights, values, maxWeight);
46    console.log(res);
47}
48
49class EOFError extends Error {}
50{
51    const gen = main();
52    const next = (line) => gen.next(line).done && process.exit();
53    let buf = "";
54    next();
55    process.stdin.setEncoding("utf8");
56    process.stdin.on("data", (data) => {
57        const lines = (buf + data).split("\n");
58        buf = lines.pop();
59        lines.forEach(next);
60    });
61    process.stdin.on("end", () => {
62        buf && next(buf);
63        gen.throw(new EOFError());
64    });
65}
66
1function knapsack(weights: number[], values: number[], remainingWeight: number): number {
2    const n = weights.length;
3    const maxValue = new Array(n + 1);
4    for (let i = 0; i <= n; i++) {
5        maxValue[i] = new Array(remainingWeight + 1).fill(0);
6    }
7    for (let i = 0; i <= n; i++) {
8        for (let w = 0; w <= remainingWeight; w++) {
9            if (i === 0 || w === 0) {
10                maxValue[i][w] = 0;
11            } else if (w < weights[i - 1]) {
12                maxValue[i][w] = maxValue[i - 1][w];
13            } else {
14                maxValue[i][w] = Math.max(
15                    values[i - 1] + maxValue[i - 1][w - weights[i - 1]],
16                    maxValue[i - 1][w],
17                );
18            }
19        }
20    }
21    return maxValue[n][remainingWeight];
22}
23
24function splitWords(s: string): string[] {
25    return s === "" ? [] : s.split(" ");
26}
27
28function* main() {
29    const weights = splitWords(yield).map((v) => parseInt(v));
30    const values = splitWords(yield).map((v) => parseInt(v));
31    const maxWeight = parseInt(yield);
32    const res = knapsack(weights, values, maxWeight);
33    console.log(res);
34}
35
36class EOFError extends Error {}
37{
38    const gen = main();
39    const next = (line?: string) => gen.next(line ?? "").done && process.exit();
40    let buf = "";
41    next();
42    process.stdin.setEncoding("utf8");
43    process.stdin.on("data", (data) => {
44        const lines = (buf + data).split("\n");
45        buf = lines.pop() ?? "";
46        lines.forEach(next);
47    });
48    process.stdin.on("end", () => {
49        buf && next(buf);
50        gen.throw(new EOFError());
51    });
52}
53
1#include <algorithm>
2#include <iostream>
3#include <iterator>
4#include <limits>
5#include <sstream>
6#include <string>
7#include <vector>
8
9int knapsack(std::vector<int>& weights, std::vector<int>& values, int max_weight) {
10    int n = weights.size();
11    // 2D dp array, where max_value[i][j] is the maximum knapsack value when
12    // considering the first i items with a max weight capacity of j
13    std::vector<std::vector<int>> max_value(n + 1, std::vector<int>(max_weight + 1));
14    // iterate through all items
15    for (int i = 0; i <= n; i++) {
16        // and all possible available weights
17        for (int w = 0; w <= max_weight; w++) {
18            if (i == 0 || w == 0) {
19                // if we consider no items or no weight, the max value is 0
20                max_value[i][w] = 0;
21            } else if (w < weights[i - 1]) {
22                // if the weight of the current item exceeds the max available weight,
23                // then the answer is the max value when considering the first i - 1 items
24                max_value[i][w] = max_value[i - 1][w];
25            } else {
26                // otherwise, we choose the best option between either:
27                // picking up: item's value + max value when considering the rest of the items and a new weight
28                // giving up: similar to the condition above
29                max_value[i][w] = std::max(
30                    values[i - 1] + max_value[i - 1][w - weights[i - 1]],
31                    max_value[i - 1][w]);
32            }
33        }
34    }
35    // the answer is the max value when considering all n items and available weight of max_weight
36    return max_value[n][max_weight];
37}
38
39template<typename T>
40std::vector<T> get_words() {
41    std::string line;
42    std::getline(std::cin, line);
43    std::istringstream ss{line};
44    ss >> std::boolalpha;
45    std::vector<T> v;
46    std::copy(std::istream_iterator<T>{ss}, std::istream_iterator<T>{}, std::back_inserter(v));
47    return v;
48}
49
50void ignore_line() {
51    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
52}
53
54int main() {
55    std::vector<int> weights = get_words<int>();
56    std::vector<int> values = get_words<int>();
57    int max_weight;
58    std::cin >> max_weight;
59    ignore_line();
60    int res = knapsack(weights, values, max_weight);
61    std::cout << res << '\n';
62}
63

The table fills from smaller subproblems to larger ones. Each cell depends only on the previous row:

Space Optimization

Since each row only uses the previous row, we reduce to a 1D array by iterating capacities right-to-left. This ensures dp[j - weight] still holds the previous row's value when we update dp[j].

1def knapsack(weights: list[int], values: list[int], max_weight: int) -> int:
2    # initialize the array and set values to -1 except for index 0
3    dp = [-1] * (max_weight + 1)
4    dp[0] = 0
5    # loop through the objects
6    for i in range(len(weights)):
7        # loop through the dp indexes from largest value to smallest one
8        for j in range(max_weight, weights[i] - 1, -1):
9            # check if we have reached the weight value before
10            if dp[j - weights[i]] != -1:
11                dp[j] = max(dp[j], dp[j - weights[i]] + values[i])
12    return max(dp)
13
14if __name__ == "__main__":
15    weights = [int(x) for x in input().split()]
16    values = [int(x) for x in input().split()]
17    max_weight = int(input())
18    res = knapsack(weights, values, max_weight)
19    print(res)
20
1import java.util.Arrays;
2import java.util.List;
3import java.util.Scanner;
4import java.util.stream.Collectors;
5
6class Solution {
7    public static int knapsack(List<Integer> weights, List<Integer> values, int maxWeight) {
8        // make a dp array and fill the array with -1 making sure to set weight 0 to value 0
9        int[] dp = new int[maxWeight + 1];
10        Arrays.fill(dp, -1);
11        dp[0] = 0;
12        // loop through every object which is simply length of weights array, values array also works as they should be same length
13        for (int i = 0; i < weights.size(); i++) {
14            // as discussed make sure to loop from highest value backwards to avoid reusing the same object
15            for (int j = maxWeight; j >= weights.get(i); j--) {
16                // if we establish a particular weight is achievable we update out current weight maximum value
17                if (dp[j - weights.get(i)] != -1) {
18                    dp[j] = Math.max(dp[j], dp[j - weights.get(i)] + values.get(i));
19                }
20            }
21        }
22        int maxValue = -1;
23        for (int i = 0; i < maxWeight + 1; i++) {
24            maxValue = Math.max(maxValue, dp[i]);
25        }
26        return maxValue;
27    }
28
29    public static List<String> splitWords(String s) {
30        return s.isEmpty() ? List.of() : Arrays.asList(s.split(" "));
31    }
32
33    public static void main(String[] args) {
34        Scanner scanner = new Scanner(System.in);
35        List<Integer> weights = splitWords(scanner.nextLine()).stream().map(Integer::parseInt).collect(Collectors.toList());
36        List<Integer> values = splitWords(scanner.nextLine()).stream().map(Integer::parseInt).collect(Collectors.toList());
37        int maxWeight = Integer.parseInt(scanner.nextLine());
38        scanner.close();
39        int res = knapsack(weights, values, maxWeight);
40        System.out.println(res);
41    }
42}
43
1"use strict";
2
3function knapsack(weights, values, maxWeight) {
4    // initialize the dp array and set values to -1 except for index 0
5    const dp = Array(maxWeight + 1).fill(-1);
6    dp[0] = 0;
7    // loop through the objects
8    for (let i = 0; i < weights.length; i++) {
9        // loop through the dp indexes from largest value to smallest value
10        for (let j = maxWeight; j >= weights[i]; j--) {
11            // check if we have reached the weight value before
12            if (dp[j - weights[i]] !== -1) {
13                dp[j] = Math.max(dp[j], dp[j - weights[i]] + values[i]);
14            }
15        }
16    }
17    return Math.max(...dp);
18}
19
20function splitWords(s) {
21    return s === "" ? [] : s.split(" ");
22}
23
24function* main() {
25    const weights = splitWords(yield).map((v) => parseInt(v));
26    const values = splitWords(yield).map((v) => parseInt(v));
27    const maxWeight = parseInt(yield);
28    const res = knapsack(weights, values, maxWeight);
29    console.log(res);
30}
31
32class EOFError extends Error {}
33{
34    const gen = main();
35    const next = (line) => gen.next(line).done && process.exit();
36    let buf = "";
37    next();
38    process.stdin.setEncoding("utf8");
39    process.stdin.on("data", (data) => {
40        const lines = (buf + data).split("\n");
41        buf = lines.pop();
42        lines.forEach(next);
43    });
44    process.stdin.on("end", () => {
45        buf && next(buf);
46        gen.throw(new EOFError());
47    });
48}
49
1function knapsack(weights: number[], values: number[], remainingWeight: number): number {
2    const n = weights.length;
3    const maxValue = new Array(n + 1);
4    for (let i = 0; i <= n; i++) {
5        maxValue[i] = new Array(remainingWeight + 1).fill(0);
6    }
7    for (let i = 0; i <= n; i++) {
8        for (let w = 0; w <= remainingWeight; w++) {
9            if (i === 0 || w === 0) {
10                maxValue[i][w] = 0;
11            } else if (w < weights[i - 1]) {
12                maxValue[i][w] = maxValue[i - 1][w];
13            } else {
14                maxValue[i][w] = Math.max(
15                    values[i - 1] + maxValue[i - 1][w - weights[i - 1]],
16                    maxValue[i - 1][w],
17                );
18            }
19        }
20    }
21    return maxValue[n][remainingWeight];
22}
23
24function splitWords(s: string): string[] {
25    return s === "" ? [] : s.split(" ");
26}
27
28function* main() {
29    const weights = splitWords(yield).map((v) => parseInt(v));
30    const values = splitWords(yield).map((v) => parseInt(v));
31    const maxWeight = parseInt(yield);
32    const res = knapsack(weights, values, maxWeight);
33    console.log(res);
34}
35
36class EOFError extends Error {}
37{
38    const gen = main();
39    const next = (line?: string) => gen.next(line ?? "").done && process.exit();
40    let buf = "";
41    next();
42    process.stdin.setEncoding("utf8");
43    process.stdin.on("data", (data) => {
44        const lines = (buf + data).split("\n");
45        buf = lines.pop() ?? "";
46        lines.forEach(next);
47    });
48    process.stdin.on("end", () => {
49        buf && next(buf);
50        gen.throw(new EOFError());
51    });
52}
53
1#include <algorithm>
2#include <iostream>
3#include <iterator>
4#include <limits>
5#include <sstream>
6#include <string>
7#include <vector>
8
9int knapsack(std::vector<int>& weights, std::vector<int>& values, int max_weight) {
10    // initialize the dp array and set values to -1 except for index 0
11    std::vector<int> dp(max_weight + 1, -1);
12    dp[0] = 0;
13    // loop through every object which is simply length of weights array, values array also works as they should be same length
14    for (int i = 0; i < weights.size(); i++) {
15        // as discussed make sure to loop from highest value backwards to avoid reusing the same object
16        for (int j = max_weight; j >= weights[i]; j--) {
17            // if we establish a particular weight is achievable we update out current weight maximum value
18            if (dp[j - weights[i]] != -1) {
19                dp[j] = std::max(dp[j], dp[j - weights[i]] + values[i]);
20            }
21        }
22    }
23    return *std::max_element(dp.begin(), dp.end());
24}
25
26template<typename T>
27std::vector<T> get_words() {
28    std::string line;
29    std::getline(std::cin, line);
30    std::istringstream ss{line};
31    ss >> std::boolalpha;
32    std::vector<T> v;
33    std::copy(std::istream_iterator<T>{ss}, std::istream_iterator<T>{}, std::back_inserter(v));
34    return v;
35}
36
37void ignore_line() {
38    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
39}
40
41int main() {
42    std::vector<int> weights = get_words<int>();
43    std::vector<int> values = get_words<int>();
44    int max_weight;
45    std::cin >> max_weight;
46    ignore_line();
47    int res = knapsack(weights, values, max_weight);
48    std::cout << res << '\n';
49}
50

Time Complexity: O(n × max_weight)

Space Complexity: O(max_weight)

Invest in Yourself
Your new job is waiting. 83% of people that complete the program get a job offer. Unlock unlimited access to all content and features.
Go Pro