← Back to Data Structures & Algorithms

Knapsack and optimisation problems

Knapsack problems ask how to choose items under a limit to maximise value. They show both the power of DP and its limits.

The 0/1 knapsack problem

Given items with weights and values and a bag of capacity W, choose a subset with total weight at most W and maximum total value; each item is taken whole or not at all. Trying all subsets takes O(2^n). A greedy choice by value-to-weight ratio can fail, because a high-ratio small item may block a better combination.

The knapsack recurrence

State: K[i][w] = best value using the first i items with capacity w. Either skip item i, giving K[i - 1][w], or take it if it fits, giving value[i] + K[i - 1][w - weight[i]]. K[i][w] is the larger of these. The table has (n + 1)(W + 1) entries, each O(1), so the algorithm takes O(nW) time.

Pseudo-polynomial time

O(nW) looks polynomial, but W is a number, and writing it needs only about log2(W) bits. If capacities are huge, say 10^15, the table is impractically large. Such algorithms are called pseudo-polynomial. The 0/1 knapsack decision problem is NP-complete, so no truly polynomial algorithm is known.

Variants

In the unbounded knapsack, each item can be used any number of times, so K[w] = max over items of value + K[w - weight]. The fractional knapsack, where items can be split, is solved exactly by the greedy ratio method in O(n log n). Subset sum, deciding if some subset reaches exactly a target, is a knapsack special case.

DP on trees and DAGs

DP works on any structure whose subproblems form a DAG with no circular dependencies. On a tree, compute answers for children before parents: for example, the maximum independent set of a tree, the largest set of vertices with no two adjacent, uses two values per node, with and without that node. Longest paths in DAGs follow a topological order.

Bitmask DP and its limits

When the state includes a subset of up to about 20 items, encode it as a bitmask. The Held-Karp algorithm solves the travelling salesperson problem exactly in O(n^2 2^n), much better than the n! of brute force but still exponential, practical only for a few dozen cities. Such state explosions mark the boundary of what DP can do.

DP in practice

Dynamic programming appears in speech recognition (the Viterbi algorithm for hidden Markov models), bioinformatics sequence alignment (Needleman-Wunsch and Smith-Waterman), text justification in word processors, resource allocation, and reinforcement learning, where Bellman's equations define optimal decision policies.

Worked example

Capacity 5; items A (weight 2, value 3), B (weight 3, value 4), C (weight 4, value 5). Greedy by ratio picks A (1.5), then B (1.33): weight 5, value 7. Checking with DP: K[3][5] = max(K[2][5], 5 + K[2][1]) = max(7, 5 + 0) = 7. So the best value is 7, using A and B. Taking C alone gives only 5, because nothing else then fits.

Key takeaways

The 0/1 knapsack maximises value under a weight limit; brute force is O(2^n) and greedy by ratio can fail. The DP K[i][w] = max(skip, take) runs in O(nW), which is pseudo-polynomial since W is a magnitude; the problem is NP-complete. Unbounded knapsack reuses items; fractional knapsack is solved greedily; subset sum is a special case. DP works on trees and DAGs with acyclic dependencies. Bitmask DP, such as Held-Karp's O(n^2 2^n) travelling salesperson algorithm, shows exponential limits. DP powers Viterbi decoding, sequence alignment, and reinforcement learning.

Flashcard

0/1 knapsack

Take each item whole or not at all

Maximise value under capacity.

Check your understanding

Why is the O(nW) knapsack algorithm called pseudo-polynomial?

← Previous lesson Next lesson →