Module P-13·12 min read

When state needs two dimensions, and how 0/1 knapsack differs from unbounded knapsack.

Written by Jatin Jain Saraf · Architect of SupraScan

Module P-13 — Dynamic Programming III: 2D DP and Knapsack

What this module covers: Module P-12's problems all had one dimension of state — a position in a sequence. This module adds a second: the state now depends on both a position (which items have been considered) and a resource constraint (how much capacity remains). This module covers 0/1 knapsack, its unbounded variant (which turns out to be Module P-12's Coin Change in disguise), and grid-path counting — the other common shape 2D DP takes.


Why Two Dimensions

The knapsack problem: given items, each with a weight and a value, and a bag with a maximum capacity, choose a subset of items maximizing total value without exceeding the capacity. The answer depends on two things at once: which items you're allowed to consider, and how much capacity you have left — one dimension alone can't capture that, so the DP table needs two: dp[i][w].


0/1 Knapsack: Each Item Used at Most Once

function knapsack01(weights: number[], values: number[], capacity: number): number {
  const n = weights.length;
  // dp[i][w] = max value achievable using the first i items, with capacity w remaining
  const dp: number[][] = Array.from({ length: n + 1 }, () => new Array(capacity + 1).fill(0));
 
  for (let i = 1; i <= n; i++) {
    for (let w = 0; w <= capacity; w++) {
      // Option 1: don't take item i-1 — carry forward the best result without it
      dp[i][w] = dp[i - 1][w];
 
      // Option 2: take item i-1, if it actually fits in the remaining capacity
      if (weights[i - 1] <= w) {
        dp[i][w] = Math.max(dp[i][w], dp[i - 1][w - weights[i - 1]] + values[i - 1]);
      }
    }
  }
 
  return dp[n][capacity];
}
 
knapsack01([1, 3, 4, 5], [1, 4, 5, 7], 7); // 9 (items with weight 3 and 4, values 4 + 5)

dp[i][w] = the best value achievable considering only the first i items, with w capacity available. At each cell, there are exactly two choices, mirroring House Robber's shape from Module P-12, just now indexed by two dimensions instead of one: skip the current item (dp[i-1][w], unchanged capacity, one fewer item to consider) or take it, if it fits (dp[i-1][w - weight] + value, one fewer item to consider, capacity reduced by its weight). The critical detail that makes this "0/1" (each item used at most once): both options always move from row i to row i - 1 — once an item has been considered, it's never available again in any subsequent calculation for this same subset of items.


Unbounded Knapsack: Items Can Be Reused

Change one assumption — items can be used any number of times — and the recurrence changes in exactly one, telling place: instead of stepping back to the previous row (i - 1) when taking an item, you stay on the same row (i), because the item you just took is still available to take again.

function unboundedKnapsack(weights: number[], values: number[], capacity: number): number {
  // dp[w] = max value achievable with capacity w, items reusable without limit
  const dp = new Array(capacity + 1).fill(0);
 
  for (let w = 1; w <= capacity; w++) {
    for (let i = 0; i < weights.length; i++) {
      if (weights[i] <= w) {
        dp[w] = Math.max(dp[w], dp[w - weights[i]] + values[i]); // dp[w - weight], NOT a separate "previous item" row
      }
    }
  }
 
  return dp[capacity];
}

Look closely, and this is Module P-12's Coin Change, generalized: Coin Change is exactly unbounded knapsack where every "value" equals 1 (you're minimizing coin count, not maximizing value) and every coin denomination is reusable without limit — the same "stay on the same row/array, because reuse is allowed" structural signature. Recognizing that two problems that look unrelated on the surface (making change vs. packing a bag) share the identical underlying recurrence shape is a big part of what separates "I've memorized twelve DP problems" from "I can recognize a new problem's shape" — the actual, transferable skill this course is trying to build.


The Other Common 2D Shape: Grid Paths

Sign in to keep reading

The rest of this module is free — sign in with Google to unlock it and track your progress.

Sign in & Register

Discussion

0

Join the discussion

Loading comments...