Dynamic Programming

Context: FIT2004_MOC · PT-02’s entire subject — brute force made cheap by never recomputing a subproblem; the sibling paradigm to greedy and divide & conquer Parent Framework: Algorithm

Quick Revision

  • 🎯 Objective: the lecture’s DPA: take the problem ➔ break it down (subproblems that are optimal and overlap) ➔ memoise ➔ reconstruct (decision array or backtracking).
  • 📦 Core Components: overlapping subproblems ➔ reuse instead of recompute | optimal substructure ➔ an optimum is built from optima of subproblems.
  • ⚡ Key Constraint: the marks are in the recurrence relation, and this recurrence describes the output stored in the MEMO — a different animal from PT-01’s time-complexity recurrence. Confusing the two answers the wrong question fluently.

📝 How It Works

1. Brute Force, But Smarter (the paradigm)

  • Why it is brute force ➔ it still considers every combination / choice; the choices are what the subproblems enumerate. “Can we brute force everything? Yes — but brute forcing needs too much effort.”
  • Why it is faster ➔ it does not recompute. A subproblem solved once is read from the table forever after.
  • What it costs ➔ memoisation: the table is auxiliary space that brute-force recursion never paid for.
  • The self-check ➔ auxiliary space time — every cell must be written at least once, so a DP whose quoted time is below its table size is arithmetically impossible (Algorithmic Complexity §6).
  • Why DP is hard ➔ “it isn’t easy to break problems down.” The cure the lecturer prescribes is practice on the classical problems (§11), not a formula.

2. The Two Ingredients — and the Paradigm Boundary (LO1)

  • Overlapping subproblems ➔ the same subproblem is reached by many different choice sequences, so storing its answer pays for itself.
  • Optimal substructure ➔ an optimal solution to the whole contains optimal solutions to its parts, so a table of sub-optima suffices.
  • vs Divide and Conquer — the lecture’s exact answer ➔ the two skeletons look identical (take a big thing, divide, solve the smaller one, combine back up). The difference is two words inserted into the third step: the sub-solutions are OPTIMAL, and they are reusable because the subproblems overlap. D&C’s subproblems are disjoint — Merge Sort’s halves share nothing — so there is nothing to reuse and no notion of an optimal subsolution.
  • vs greedy ➔ greedy needs optimal substructure and the greedy-choice property, and commits irrevocably. DP keeps every subproblem’s answer and combines them later, which is exactly what buys correctness when no ranking rule is safe (weighted interval scheduling · Coin Change on · the coin game).
  • Dijkstra is both ➔ DP in its reuse of sub-minima, greedy in its finalisation. Bellman-Ford and Floyd-Warshall drop the greedy half and are pure DP.

3. Fibonacci — the Motivating Example

  • The repetition is the opportunity ➔ expanding recursively recomputes twice, three times, five times. “We are repeating — adding complexity!”
  • The everyday analogy ➔ compute once, then reuse it for and . That reuse is memoisation.
  • Top-down ➔ start at the top, keep breaking into smaller problems (the smallest is the base case), then solve upward reusing the stored results. The shape is the recursion tree with a memo attached.
  • Bottom-up ➔ start from the base case, solve it, use it for the next bigger case, and continue until the final one. The shape is a loop over a table.
  • What memoisation buys here ➔ each is computed once ⟹ time, against the naive branching recursion’s ➔ Fibonacci Sequence for the closed forms and the doubling identities.
  • Why it is the right first example ➔ one parameter, one obvious base case, and the repeated subtree is visible on a slide — everything after this differs only in how hard the subproblem definition is.

4. The MEMO Is the Subproblem Definition

  • Write it as an English sentence in braces, always ➔ DP[i] = {the maximum profit obtainable from a subset of the houses [1..i]}. If you cannot write that sentence, you do not have a DP yet.
  • The MEMO’s dimensions are the subproblem’s parameters ➔ one index per thing the answer genuinely depends on; a wrong dimension count is a wrong subproblem definition, not a coding slip.
  • The MEMO shows how the solution is formed from subsolutions ➔ the recurrence is read off the definition, never invented alongside it.
  • Iterate steps 1–2 of the recipe ➔ “while some definitions seemed correct, it isn’t the case always” — brute-force first, then define, then re-check the definition against the brute force.
  • Locate the answer at definition time ➔ is it the final cell (Coin Change, the salesman, LCS) or a scan over the table? Not always the last position — LIS is the standing counterexample.

5. The Recurrence — Three Groups of Cases

  • Base case(s) ➔ the initial values you write in directly; each has exactly one optimal solution with no ambiguity, and they always exist because backtracking must terminate somewhere.
  • General case ➔ the subproblems proper; the value comes from other subproblems’ solutions, and this line is where the decision (max / min / sum / boolean or) is written. It usually contains the final answer.
  • Edge case(s) ➔ boundary subproblems that look general but need no decision, like the base cases — a grid’s top row and rightmost column, a value below the smallest coin, a knapsack with no capacity left. They may overlap with the other two depending on how you write it.
  • Order matters when cases overlap ➔ if two cases can both fire, say “cases are read top to bottom, first match wins” (the wildcard-matching problem does exactly this).
  • The canonical worked recurrence ➔ Coin Change §2 — every PT-02 problem so far has been that shape in costume.

6. Sizing the MEMO ⟹ Sizing the Complexity

  • Auxiliary space the table ➔ 1-D · 2-D · 3-D ; these dimensions are the number of subproblems.
  • Time subproblems work per subproblem ➔ Coin Change has subproblems (plus for ) and scans all coins at each ⟹ ; the salesman’s subproblems each cost ⟹ .
  • The choice set is not a dimension ➔ coins and items are the choices combined inside a subproblem. Miscounting them as a dimension is the highest-frequency complexity error in this topic.
  • The table is a lower bound on time ➔ filling every cell costs step each ➔ §1’s self-check.
  • A redundant parameter can be deleted (applied P8, P13 — the [D] move) ➔ if one index is derivable from the others, drop it and recompute it. The ferry problem’s collapses to because , turning into ; the interleaving problem’s collapses to because . Precompute the prefix sums in so the recomputation stays .
  • The mirror move — add a dimension when the state is insufficient ➔ if the optimum must revisit a position, the position is not a sufficient state (applied P7: DPleft and DPright, because which side of the street you are on changes your options). This is the same question that separates unbounded from 0/1 knapsack, and it is State-Space Graph Modelling’s test applied to a DP parameter.

7. Top-Down vs Bottom-Up

  • Complexity-wise they are the same ➔ both fill the same table with the same recurrence, and “technically both are interchangeable.”
  • Top-down ➔ large problem to small, so recursion with a memo is natural; might save some computations, since only the subproblems the recurrence actually reaches are ever visited.
  • Bottom-up ➔ small to large, so iteration; might save space, especially since there is no recursion (no call stack), and it makes the fill order explicit.
  • The lecturer’s habit ➔ “I only use bottom-up”, while noting some problems are more intuitive top-down.
  • Fill order is a correctness condition, not a style choice ➔ a bottom-up loop must visit each cell after every cell it reads. The grid recurrences below index and , so the loops run downward; interval DP must loop on range length.
  • Sentinel discipline for a memo ➔ the “not yet computed” marker must lie outside the answer’s range, which is why Coin Change initialises to and never to .

8. Reconstruction — Decision Array vs Backtracking

  • The question is usually “which”, not “how much” ➔ coin change “what are the coins?” · knapsack “what are the items?” · edit distance “what were the insert/delete/replace operations?”
  • Decision array ➔ at the moment you write a cell, also record the decision that produced it (which coin, which item, which predecessor), then walk those records back from the answer cell.
  • Store the final decision only, never the whole combination ➔ writing the full coin list at every value is “a waste of memory”; remembering the last coin added is and determines the rest by recursion.
  • Backtracking ➔ store nothing extra and re-derive each decision from the table: “which case could have produced this cell?” This is what the lecture calls leaving breadcrumbs.
  • Inclusion–exclusion is the backtracking test ➔ compare a cell with the cell the skip branch would have produced. 1 knapsack compares against the row above (same ⟹ excluded); the salesman takes house iff .
  • Step size encodes the constraint ➔ after taking house jump to (neighbour is now illegal); after including a knapsack item, move up a row and left by its weight.
  • The trade-off, as stated ➔ backtracking saves space (less auxiliary space, same space complexity); the decision array saves time (faster, because the decision is read rather than re-derived) — but either way “the time complexity lies in finding the solution still.”
  • Reconstruction is what kills space-saving tricks ➔ rolling a 2-D table down to two rows computes the value and deletes the breadcrumbs ➔ Knapsack Problem §4.

9. Subproblem Shapes That Keep Recurring (the applied sheet, curated)

  • Prefix / suffix, one sequence ➔ DP[i] over or ; take-or-skip decisions. (salesman houses · Coin Change · LIS)
  • Partition a sequence — try every cut ➔ DP[i] = best over j > i of (cost of the block [i..j-1] + DP[j]). One shape covers word break (min words forming the suffix ), text justification (min ) and the umbrella walk (min energy from important point ). Cost per subproblem is ⟹ unless the block cost can be made .
  • Two prefixes, one grid ➔ DP[i][j] over prefixes of two sequences ➔ Longest Common Subsequence (LCS).
  • A contiguous range ➔ DP[i][j] over ➔ Interval Dynamic Programming.
  • Capacity against an item set ➔ DP[i][w] ➔ Knapsack Problem.
  • A 2-D grid with directional moves ➔ DP[i][j] over cells, recursing on the legal moves ➔ §10.
  • A rooted tree ➔ DP[v] over subtrees, combining children (applied P20: the message broadcast, children served in descending order, with counting sort).

10. Grid DP — Two Problems, One Recurrence (applied P2, P3)

  • Count the paths ➔ DP[i][j] = {the number of valid paths from cell (i,j) to (n,n)}, moving up or right, blocked cells excluded:
  • Why the two path sets do not overlap ➔ paths through and through are disjoint, because a valid path cannot use both; so the counts add rather than needing inclusion–exclusion.
  • Collect the most money ➔ the same skeleton with instead of and the cell’s value added: , with the top row and rightmost column as edge cases and .
  • Answer ➔ in both; subproblems at ⟹ time and space.
  • Symmetry ➔ defining as paths from to and reading is equally valid — the base and edge cases mirror. Pick one direction and keep the indices consistent; mixing them is the classic grid bug.
  • The three edge cases are the boundary ➔ top row () and rightmost column () have only one legal move, so they are decision-free ➔ §5.

11. The Classical Problem Roster (know where each one lives)

ProblemTierShapeNote
Fibonaccipass1-D, one predecessor pairthe motivating example ➔ §3
Coin Changepass1-D over value, choicesPT-02’s costume of choice
Unbounded knapsackpass1-D over weightcoin change with , init
1 knapsackpass2-D, items weightthe row is “which items are on offer”
Rod cuttingpass1-D over lengthon the wrap-up’s list; not in the lecture deck — it is unbounded knapsack with length as weight
Edit distancepass2-D, two prefixesdeliberately skipped in the lecture, covered in the tutorial videos linked to LCS
LCScredit2-D, two prefixesthe sheet’s hint calls it “very similar to edit distance”
LIScredit1-D, anchoredanswer is a scan, not the last cell
Matrix chain multiplicationcreditrange, split at ➔ Interval Dynamic Programming §5
Everything on the applied sheetcreditvarious➔ §9 and FIT2004 Unit Cheatsheet §1️⃣2️⃣

⚙️ Core Implementation

🔹 The salesman’s houses — fill inclusion–exclusion backtracking (applied P1)

⚖️ Core Decision Matrix

SituationParadigmWhyDeliverable
Subproblems disjoint, no optimisationDivide and Conquernothing repeats ⟹ no table pays for itselfthe split/combine step
Optimal substructure greedy-choice propertyGreedyone irrevocable choice per step skips the searchthe exchange / stays-ahead proof
Optimal substructure, no safe ranking ruleDynamic programmingkeep every subproblem’s answer, decide laterthe recurrence relation
Overlapping subproblems, no optimisation (counting)Dynamic programmingreuse still removes the exponentialthe recurrence, with not
Neither property holdsbrute force / backtrackingexhaustive or the search-space bound

When It Flips: the boundary between greedy and DP is the greedy-choice property alone — both need optimal substructure. Weighted interval scheduling keeps the substructure and loses the choice property, so it flips to DP; coin change on and the coin game flip for the same reason.

📊 Exam Execution Trace & Applied Exercises

Manual Execution Trace — the salesman,

, for , , .

(skip) (take)Winner
——base
skip
take
take
skip
take
take
take
take
take

Backtracking pass (inclusion–exclusion, no decision array)

vs ActionNext
take
take
take
take
skip
take ➔ stop

Final Extracted Output: \mathbf{\252}{1,4,6,8,10}7100$) and is not in the optimum.

  • Read the trap ➔ the taken set is not the set of rows where “take” won during the fill; only the backtracking pass identifies it. Row ‘s take branch won yet house is not sold to.

Applied Exercise — the PT-02 recurrence-selection question (sample [PT2W8])

Problem: microwave keys , each pressable any number of times. the minimum key presses to enter time . Select the correct clauses.

Final Extracted Output: clauses (a), (g), (i). Why each rival dies: ∞ if t ≤ 0 contradicts the base · 1 if t=0 charges a press for entering nothing · max maximises presses · counts every key instead of choosing one · dropping the forgets to charge for the press just made. Sanity check the definition, not the algebra: presses (two s, five s).

  • The transferable move ➔ this is Coin Change with and . Every PT-02 problem is a classical problem in costume — identify the costume first ➔ §11.

⚠️ Common Mistakes

  • 💡 Writing a time-complexity recurrence instead of an output recurrence ➔ PT-01’s describes cost; PT-02’s describes the answer stored in cell . Same word, different object.
  • 💡 Counting the choice set as a MEMO dimension ➔ coin change is space, not ; the coins are work inside each subproblem, so they appear in the time only.
  • 💡 Calling DP “just divide and conquer with a cache” ➔ the lecture’s answer is “NO”: D&C subproblems are disjoint and carry no notion of an optimal subsolution ➔ §2.
  • 💡 Assuming the answer is the last cell ➔ true for coin change and the salesman, false for LIS and maximum subarray. Locate the answer when you define the MEMO, not when you debug.
  • 💡 Skipping the edge cases ➔ a general case that indexes on the last row is an out-of-bounds read or a silent wrong answer; the boundary is a case, not an implementation detail.
  • 💡 Returning the value when the question asked for the combination ➔ “which houses / coins / items” needs a decision array or a backtracking pass ➔ §8.
  • 💡 Quoting bottom-up as “faster than top-down” ➔ same complexity; top-down wins only when subproblems can be skipped, bottom-up wins on the missing recursion stack and on clarity.

🧠 Active Recall