COMPUTER ENGINEER

← BlogDATA STRUCTURES / ALGORITHMSPython example pack ↓

Algorithm design · 35 / 53

DP: states, transitions, order and reconstruction

Understand → trace → implement → justify

2 min reading · allow extra time for practice

DP is a problem model, not merely a cache trick. Define each state exactly, derive transitions from the final decision, and specify base/impossible states. Tabulation needs dependency order; memoisation visits only reached states.

Minimum coins uses dp[0]=0 and dp[x]=min(dp[x−c]+1), with positive coins. The optimum count does not reveal selected coins; retain choices for reconstruction.

State must preserve all information needed by future decisions. Analyse number of states times transition cost. Knapsack O(nW) is pseudo-polynomial in numeric capacityW rather than polynomial in its encoded bit length.

Make the DP state explicit

For coins {1,3,4} and target six, greedy selects 4+1+1, using three coins. The optimum is 3+3. Let dp[x] mean the minimum coins for exactly x. Set dp[0]=0 and initialise other states to +∞. Transition dp[x]=min(dp[x−c]+1) for c≤x. Increasing x ensures dependencies are ready; unreachable states remain infinite.

x0123456
dp[x]0121122

Store the selected coin in parent[x] to reconstruct a solution by walking back to zero. A tie-break rule makes output deterministic. Returning a count differs from returning a witness.

Correctness requires a state that captures optimal substructure. Ask which past information future choices need. Single-use coins require a different transition from unlimited coins. In one-dimensional 0/1 knapsack, the wrong capacity-loop direction can reuse one item.

Foundation: Derive dp[6]. Intermediate: Reconstruct the coin list. Advanced: Explain why O(target·k) is pseudo-polynomial when target is binary-encoded; specify unreachable amounts and zero/negative coin contracts.

A worked trace

Coins1,3,4 give dp=[0,1,2,1,1,2,2]; choices6→3→0 reconstruct3+3.

Cost and assumptions

TargetA andk coins: O(Ak) time, O(A) space; pseudo-polynomial in encodedA.

Executable example

Run with Python 3. Assertions check a small example; they do not constitute a general correctness proof. Some advanced examples are explicitly small models or reference oracles, not full production implementations.

Python 3
def min_coins(coins, target):
    if target < 0 or any(c <= 0 for c in coins): raise ValueError("invalid input")
    dp = [0]+[float("inf")]*target
    for x in range(1,target+1):
        for c in coins:
            if c <= x: dp[x]=min(dp[x],1+dp[x-c])
    return None if dp[target] == float("inf") else dp[target]
assert min_coins([1,3,4],6) == 2

TEST YOUR UNDERSTANDING

Your turn

What risk does coin0 create in recursive memoised DP?

Reveal the reasoning

The state does not shrink and recurses into itself before caching. Require positive denominations.

Take it further

  1. Write down the input contract and the invariant before changing the example.
  2. Add empty, boundary, duplicate and adversarial cases where they are relevant. Compare with a simple oracle.
  3. Derive the cost under the stated model; measure several input sizes and explain discrepancies.

Primary reading & lecture notes

Original explanations in this course; these references provide proofs and further reading. Source links may cover the broader module.

MIT 6.006 · Introduction to Algorithms ↗Jeff Erickson · Algorithms ↗
Solve the exercise before moving on.