CIS 3490 — Design & Analysis of Algorithms
interactive studio · pick a tool and play
⚠ EXAM MONDAY 2:30 PM · WRONG FIRST LINE = ZERO MARKS · TARGET 38/50
Section A: no partial marks · Section B (15): asymptotic analysis · Section C (10): algorithm tracing · Section D (15): design
keyboard: 1–9 tools · t trace · d design · m mock · p plan · ? panic · esc home
💾 your Flashcards "known" set and Design Bank self-ratings persist across reloads
📊 your progress · estimated exam-readiness
🆕 RECENT UPDATES · click to expand · built while you were away
- ⚡ Bellman-Ford · neg weights + cycle detect
- 🔢 Gaussian Elimination · partial pivoting
- 🌲 Heapsort · bottom-up + sift-down
- ⚖ AVL Tree · all 4 rotation types
- ⚡ Quicksort · Hoare partition + recursion log
- 📊 Presorting Walkthrough · 5 problems
- ✕ Strassen's · 7-mult D&C
- ≡ Horner's Rule + LCM↔GCD demo
- △ Pascal's Triangle · 4 modes + DP
- ⊞ Sorted Matrix Search · O(n) corner walk
- 🕸 DAG Path Counter · Addition Rule + lattice
Live per-line hit counts on every step-emitting animator (Sort, Search, Heapsort, Quicksort, Bellman-Ford, Gauss, Matrix Search). Each line gets ✓ when fired; "COVERAGE COMPLETE" appears when every executable line has been hit, including both branches of every IF. Closes the user's "every line must be hit" requirement.
- · Live text filter on tiles
- · 10 paradigm category chips (Analyze, Sort, Graph, T&C, D&C, DP, Greedy, Combo, Practice)
- · 📚 Coverage Map: syllabus-organized topic → program crosswalk (~59 links)
- · Distinct tile colors on every program
- · Per-page context for ALL 37 views
- · Now injects what algorithm you're studying into every Twin query automatically
A2 added (was missing). All 90 marks of practice covered: A1 (10×3=30) + A2 (6×5=30) + A3 (5×6=30). Each question has its own solution reveal + links to the matching interactive program.
All 9 chapters covered: Ch1 asymptotics · Ch2 brute force · Ch3 decrease & conquer · Ch4 graphs · Ch5 D&C · Ch6 T&C (all 3 parts) · Ch7 trees · Ch8 DP · Ch9 greedy · plus combinatorics. Lecture PDFs read: T&C Ch6 ×3, Quicksort, D&C, Decrease summary, Pascal, perms/combs.
Sort Visualizer Q14–Q19
animated insertion · selection · bubble · merge with comparison & swap counters
📊 Line Coverage — proof every algorithm line is hit
Counts every step the animation emits per pseudocode line (incl. both TRUE and FALSE branches of every IF). After a complete run, every executable line should have count ≥ 1.
How insertion sort works
Bounds Visualizer Q1–Q5
drag c₁ / c₂ / n₀ — see when O, Ω, Θ hold
Big-O Proof Workshop Q6
3-step proof builder · prove f(n) ∈ O(g(n)) by definition
1️⃣ "Need c > 0, n₀ ≥ 1 such that f(n) ≤ c·g(n) for all n ≥ n₀." — definition line
2️⃣ For each lower term: bound it by a multiple of g(n). (e.g. 5n ≤ 5n² when n ≥ 1; 100 ≤ n² when n ≥ 10)
3️⃣ Sum the coefficients → that's your c. Pick the strictest threshold → that's your n₀.
DFS / BFS Playground Q20–Q24
click empty space to add a node · click two nodes to add an edge · ▶ to traverse
DFS pseudocode (highlights live during traversal)
DFS(G): for each v ∈ V: mark[v] ← 0 # unvisited count ← 0 for each v ∈ V: if mark[v] = 0: DFS_VISIT(v) DFS_VISIT(v): count ← count + 1 mark[v] ← count for each unvisited w adj to v: DFS_VISIT(w) # edge types: TREE (to unvisited) · BACK (to ancestor = CYCLE) # complexity: Θ(|V| + |E|) on adj list
BFS pseudocode (highlights live during traversal)
BFS(G, s): initialize queue Q mark s as visited Q.enqueue(s) while Q ≠ ∅: u ← Q.dequeue() for each unvisited w adj to u: mark w as visited Q.enqueue(w) # edge types: TREE (to unvisited) · CROSS (same/adj BFS level) # gives shortest path (in # edges, unweighted) # complexity: Θ(|V| + |E|) on adj list
⚠ Section C exam tip: when you trace a graph, write the pseudocode FIRST, then the iteration steps. Both are graded. Always label edges as Tree/Back/Cross.
Master Theorem Trainer Q13
T(n) = a·T(n/b) + f(n) — pick a, b, f and the case is identified
Let
k = log_b(a). Then compare f(n) to n^k:• Case 1: f(n) = O(n^(k−ε)) → T(n) = Θ(n^k)
• Case 2: f(n) = Θ(n^k) → T(n) = Θ(n^k · log n)
• Case 3: f(n) = Ω(n^(k+ε)) + regularity → T(n) = Θ(f(n))
Examples: merge sort 2T(n/2)+n → k=1, f=n → Case 2 → Θ(n log n). Binary search T(n/2)+1 → k=0, f=1 → Case 2 → Θ(log n).
📝 Fill-in-the-Blank Quiz
Pick a recurrence, fill every blank from a dropdown, submit to grade. Exam-format step-by-step.
DP Table Walker Q45–Q48
non-adjacent max-sum · weighted activity selection · weighted interval scheduling (jobs) · fill cells one at a time
50-Question Flashcards Q1–Q50
every question from the cheatsheet · click card to flip · ← → to navigate
Professor Twin DeepSeek
chat tutor primed on CIS 3490 — ask anything, work through problems
backed by deepseek-chat · system prompt loaded with cheatsheet · stateless per turn
First-Move Drill EXAM CRITICAL
type the exact opening line for each problem · wrong = zero marks
⚠ THE RULE
Wrong first term = ZERO for entire question. No alternative methods accepted. No partial marks in Section A. Section B questions are worth 5 marks each — your first line alone is typically worth 2.
Drill until you can write each opening cold in under 10 seconds.
MC Blitz · Section A 10 marks
10 MC + 5 SA · 60 seconds each · NO partial marks · from real midterm + 4 mock exams
Trace Mode · Section C 10 marks
step through the exact exam arrays · marking-scheme table format · 2 trace questions × 5 marks
⚠ MARKING SCHEME REMINDER
Section C trace questions are graded on the table format above plus the derivation line below. Must use the technique asked (insertion = shift+insert, selection = find-min+swap, DFS = stack-based, BFS = queue-based). Alternative algorithms = 0 marks even if correct.
Always end with: C_worst(n) = Σ_{i=1}^{n-1} i = n(n−1)/2 ∈ Θ(n²) (insertion/selection) or Tree edges: ... | Back/Cross edges: ... (DFS/BFS).
Section D Design Bank 15 marks
12 real exam design problems · write pseudocode, reveal marking-scheme answer, self-rate
Study Plan · 48 hours target 38/50
official Master Plan schedule · each slot mapped to the right tool here
⏱ TIMELINE
Exam: Monday 2:30 PM · Now: Saturday/Sunday · Target: 38/50 (75%) — drop up to 12 marks and still pass.
Failure mode (per the Master Plan diagnosis): "conflates understanding with retrieval. The exam tests retrieval speed not depth." Every program here is timed/graded for retrieval.
📅 SATURDAY NIGHT (10 PM → 1 AM, then sleep)
| 10–11 PM | Big-O / Ω / Θ definitions + limit method | |
| 11 PM–12 AM | Recurrence setup from pseudocode | |
| 12–1 AM | Backward substitution — easy cases first |
→ SLEEP 6 hours minimum. Memory consolidates overnight.
📅 SUNDAY (7 AM → 10 PM)
| 7–9 AM | Backward sub hard case: T(n)=2T(n/2)+n — merge sort, most-tested | |
| 9–10 AM | Summation method — nested loops, S1/S2 formulas | |
| 10–11 AM | Sorting complexity derivation — insertion + selection worst case from Σ | |
| 11–12 PM | DFS + BFS traces — label tree/back/cross edges | |
| 12–1 PM | BREAK — eat, walk, NO SCREEN | mandatory |
| 1–3 PM | ⚠ MOCK EXAM — full simulation. Timed. No notes. No Claude. | |
| 3–4 PM | Fix ONLY mock failures — circled questions only, write correct method once, move on | |
| 4–5 PM | Brute force complexity — TSP O(n!), Knapsack O(2ⁿ), Assignment O(n³), Hull O(n³), ClosestPair Θ(n²) | |
| 5–6 PM | Johnson-Trotter — find largest mobile → swap → reverse all larger. Trace n=3 fully. | |
| 6–7 PM | Section A definitions blitz — 60 seconds per term, cold | |
| 7–8 PM | ★ FIRST-MOVE SETUPS for every problem type — THE MOST IMPORTANT SESSION | |
| 8 PM → | REST — no studying. Walk. Eat. Wind down. Sleep 9 hours. | structural, not optional |
📅 MONDAY (6 AM → 2:30 PM exam)
| 6–8 AM | Cold recall ONLY — write every formula and first-move setup from memory, no notes | |
| 8 AM–12 PM | Passive skim only — read your own Sunday notes, no new problems | |
| 12–2 PM | Travel and rest — nothing new | eat, arrive early |
| 2:30 PM | ⚠ EXAM | 38/50 |
THE NON-NEGOTIABLE RULES
- Every topic gets its time slot and then it ENDS. Physical timer. When it goes off, write DONE and move on.
- One worked example → immediate cold attempt. No passive explanation.
- Mock exam at 1 PM Sunday while FRESH — not after 8 hours of grinding.
- After mock: fix only failures. Do not re-study what you got right.
- Study ends 9 PM Sunday. Sleep 9 hours. Structural, not optional.
- Monday is recall and rest only. No new learning after 8 AM.
Mock Exams · Full Review 4 × 50 marks
all 4 mocks from MockExam.pdf · 72 questions total · click 👁 per question to reveal
After review: feed any wrong answers into if you missed the opening line, or if you missed pseudocode, or if you missed multiple-choice.
⚠ Mocks 2 (D&C), 3 (Asymptotic Deep Dive), and 4 (Full Coverage Hardest) are in your original MockExam.pdf. Print or open them on paper for additional cold simulations.
Search Algorithms brute force + D&C
linear · binary · interpolation · step-by-step with low/mid/high markers
📊 Line Coverage — per-algorithm pseudocode hit tracking
Executable lines per algorithm. Binary search lines 7/8 (low=mid+1 / high=mid-1) should BOTH fire across a complete search unless target is at midpoint. Line 9/10 (return -1) only fires when target is absent.
Prim's MST Section C/D
Mock 1 D22 graph · edge-by-edge growth · alphabetical tie-break · line-highlighted pseudocode
Iteration table
| iter | VT | picked edge | w | total |
|---|
Pseudocode (live)
⚠ Section C/D exam reminder
When multiple candidate edges have the same min weight, the tie-break rule is: pick the edge whose NEW (non-tree) vertex comes first alphabetically. If still tied, pick the one whose tree vertex comes first alphabetically. Complexity: O(|V|²) array-based, O((V+E) log V) with a binary heap.
Dijkstra's Shortest Path single-source
same graph as Prim's · pick min unvisited · relax edges · live dist table
Distance table
| v | dist[v] | prev[v] | visited? |
|---|
Pseudocode (live)
Notes
Dijkstra requires non-negative edge weights — for negative weights use Bellman-Ford. Complexity: O(V²) array-based, O((V+E) log V) with binary heap, O(E + V log V) with Fibonacci heap. Greedy paradigm: pick the closest unvisited each step (which is provably the final shortest distance).
Bellman-Ford Shortest Path handles negative weights
|V|-1 passes · relax every edge each pass · final pass detects negative cycles · DP paradigm
Distance table (per iteration)
| v | dist[v] | prev[v] |
|---|
Pseudocode (live)
📊 Line Coverage — proof every BellmanFord line is hit
Tracks step-emit count per pseudocode line. After a complete run, all executable lines should be hit (the negative-cycle branch only fires when the chosen graph has one).
Why Bellman-Ford over Dijkstra?
Dijkstra fails with negative weights — its greedy choice (lock-in nearest unvisited) can finalize a vertex before a longer-then-cheaper-via-negative path is found. Bellman-Ford does NOT commit to any vertex; it simply relaxes every edge |V|-1 times. After |V|-1 passes, every shortest path of ≤ |V|-1 edges has stabilized. A |V|-th pass that still relaxes ANY edge ⇒ negative cycle exists.
Complexity: Θ(V·E). Slower than Dijkstra's O(E + V log V), but more general. Paradigm: Dynamic Programming — dist[v] is built up from shorter sub-paths.
Gaussian Elimination Transform & Conquer
solve Ax = b via row operations · forward eliminate → back-substitute · Θ(n³)
Augmented matrix [A | b]
Pseudocode (live)
Step narration
click ▶ run
Solution (back-substitution)
—
📊 Line Coverage — BetterForwardElimination + Back-Substitution
Tracks step-emit count per pseudocode line. Pivot-search lines (3-7) fire only when partial pivoting is enabled.
Why is it Θ(n³)?
Three nested loops: outer i (1..n-1), middle j (i+1..n), inner k (i..n+1). Total mults ≈ Σᵢ₌₁ⁿ⁻¹ (n-i)(n-i+1) ≈ Σ p² ≈ n³/3. Doubling n → 8× runtime.
Partial pivoting swaps in the row with the largest |A[j,i]| as the pivot before eliminating. Why? In floating-point, dividing by a tiny pivot (e.g. 0.00001) creates a huge multiplier that swamps precision in other rows. Pivoting keeps the multiplier ≤ 1, preserving numerical stability. It also handles A[i,i]=0 (basic algorithm crashes).
Paradigm: Transform & Conquer / Instance Simplification — transform a general system into upper-triangular (a simpler instance), then solve by back-substitution.
Heapsort + Bottom-Up Heap Transform & Conquer · Representation Change
stage 1: bottom-up heapify Θ(n) · stage 2: extract-max + sift-down (n−1)× · total Θ(n log n) · in-place
Heap (tree view) · grey = sorted-out
Pseudocode (live)
Array (1-indexed) · green = sorted region
📊 Line Coverage — HeapBottomUp + SiftDown + Heapsort wrapper
Tracks step-emit count per pseudocode line. Both child-comparison branches of SiftDown should fire (left bigger vs right bigger).
Why is heap construction Θ(n) but heapsort Θ(n log n)?
Bottom-Up Heap Construction: A node at height h sifts down at most h levels. Most nodes are near the bottom (height 0/1), so cost = Σₕ h·(nodes at h) ≈ 2n ⇒ Θ(n). (Top-down insert-one-at-a-time costs Θ(n log n) — strictly worse.)
Heapsort: Stage 1 = Θ(n) construction; Stage 2 = n−1 extractions × O(log n) sift-down each = Θ(n log n). Overall Θ(n log n). In-place: the "deleted" max goes into the freed slot at the back, so the same array becomes the sorted output. Not stable — sift-down can reorder equal keys.
Mapping (1-indexed): root = H[1] · parent(i) = ⌊i/2⌋ · left(i) = 2i · right(i) = 2i+1. Last parent = ⌊n/2⌋. Leaves at indices ⌊n/2⌋+1..n already satisfy parental dominance (no children).
Paradigm: Transform & Conquer / Representation Change — re-represent the array as a max-heap, then exploit the dominance property to extract sorted elements.
AVL Tree Builder Transform & Conquer · Rotations
insert keys · live balance factors · auto-rotate on |BF|=2 · all 4 rotation types covered
Tree (BF labeled on each node)
Rotation log
4 Rotation Types
path: R-R (right child of right child)
BF=−2, BF(right child)=−1
A→B→C ⇒ B as new root, A=B.left, C=B.right
path: L-L (left child of left child)
BF=+2, BF(left child)=+1
C←B←A ⇒ B as new root, A=B.left, C=B.right
path: L-R (zig-zag)
BF=+2, BF(left child)=−1
L-Rot at left child, then R-Rot at root
path: R-L (zig-zag)
BF=−2, BF(right child)=+1
R-Rot at right child, then L-Rot at root
BF formula: BF(node) = height(left) − height(right). AVL invariant: BF ∈ {−1, 0, +1} for every node. Height bound: h < 1.4405 log₂(n+2) − 1.3277. Search/Insert/Delete: Θ(log n) worst case.
Quicksort + Hoare Partition D&C · in-place
pivot = A[l] · scan i→ from left, ←j from right · swap on cross · recurse
Array · pink=pivot · gold=i · purple=j · green=sorted position locked
Recursion tree (subarrays)
Partition pseudocode (live)
📊 Line Coverage — proof every Partition/Quicksort line is hit
Tracks step-emit count per pseudocode line. Both TRUE and FALSE branches of every IF should fire across a complete sort.
Why partition is the soul of Quicksort
Hoare partition uses two scanning indices that walk toward each other. Index i scans left-to-right past anything strictly less than the pivot. Index j scans right-to-left past anything strictly greater than the pivot. Both stop at equality — this is critical for duplicates (otherwise an all-equal array splits 0 / n-1 and we get Θ(n²)). When i < j we swap A[i] ↔ A[j] and advance both. When i ≥ j we swap pivot ↔ A[j] to place pivot in its final position; j is returned as the split.
Recurrence: T(n) = T(k) + T(n−k−1) + Θ(n) where k = elements smaller than pivot. Best: k = n/2 each level ⇒ T(n)=2T(n/2)+n ⇒ Θ(n log n). Worst: k = 0 or n−1 (sorted, pivot=first ⇒ smallest each time) ⇒ T(n)=T(n−1)+n ⇒ Θ(n²). Average: ≈ 1.39·n log₂n — only ~39% slower than the theoretical optimum.
Quicksort is in-place (no auxiliary array like mergesort) but not stable (swaps can reorder equal keys). Median-of-three pivoting + Randomization push the worst case toward improbable.
Paradigm: Divide & Conquer — but unusual because all the work happens in the divide step (partitioning), none in the combine step (subarrays are already in their final relative regions).
Presorting Walkthrough Transform & Conquer · Instance Simplification
brute force vs presort: 5 classic problems · same input, see the speedup
Element Uniqueness
Brute Force · Θ(n²)
Presort · Θ(n log n)
The Big Lesson
Presorting trades the up-front cost of an O(n log n) sort for the dramatic simplification of the post-sort problem. Worth it when the post-sort algorithm is linear (so total is dominated by the sort) and you'd otherwise pay quadratic. Not worth it for a single sequential search (n log n + log n > n).
Searching m times on the same data: m·n (sequential) vs n log n + m log n (sort+binary). Crossover at m ≈ log n.
Paradigm: Transform & Conquer · Instance Simplification — transform an arbitrary array into a sorted one (simpler instance), then solve.
Strassen's Matrix Multiplication D&C · Θ(n^log₂7)
brute force Θ(n³) vs Strassen Θ(n^2.807) · live 2×2 trace with all 7 M-products
Matrix A (2×2)
Matrix B (2×2)
Preset
Brute Force · Θ(n³) · 8 mults
Strassen · Θ(n^log₂7) ≈ Θ(n^2.807) · 7 mults
Result C = A × B (both methods must agree)
Why does saving 1 multiplication matter so much?
For 2×2 the difference is trivial (7 vs 8 mults). But Strassen recurses: when n>2, each of the 7 sub-products is itself an (n/2)×(n/2) matrix multiplication done via Strassen. The recurrence is M(n) = 7M(n/2). By the Master Theorem (a=7, b=2, f(n)=Θ(n²)): a > b^d (7 > 4) ⇒ T(n) ∈ Θ(n^log_b a) = Θ(n^log₂7) ≈ Θ(n^2.807). Better than Θ(n³) by a polynomial factor.
The 7 magic products: M1 = (A00+A11)(B00+B11), M2 = (A10+A11)·B00, M3 = A00·(B01−B11), M4 = A11·(B10−B00), M5 = (A00+A01)·B11, M6 = (A10−A00)(B00+B01), M7 = (A01−A11)(B10+B11). Then: C00 = M1+M4−M5+M7, C01 = M3+M5, C10 = M2+M4, C11 = M1+M3−M2+M6. 7 multiplications + 18 additions.
Trade-off: Strassen uses 18 additions vs brute-force's 4 additions per 2×2. Constant overhead means Strassen only wins for large n (crossover ≈ 100 in practice). The naive D&C split (8 sub-products) gives the same Θ(n³) — Strassen's insight was that the algebraic identity reduces 8 to 7.
Paradigm: Divide & Conquer with algebraic refinement. Faster algorithms exist (Coppersmith-Winograd O(n^2.376), more recent ~O(n^2.371)), but huge hidden constants make them impractical.
Horner's Rule + Problem Reduction T&C · Representation Change
brute force Θ(n²) vs Horner Θ(n) · nested multiplications · plus LCM↔GCD reduction
Polynomial
Brute Force · Θ(n²)
Horner's Rule · Θ(n)
Result p(x)
Why Horner's Rule works
The insight: Brute force computes each x^i from scratch (no shared work). Horner factors the polynomial into nested form:
p(x) = (...((aₙ·x + aₙ₋₁)·x + aₙ₋₂)·x + ... + a₁)·x + a₀
Each iteration does one multiplication and one addition. n iterations total ⇒ n mults, n adds, total Θ(n). Brute force does (n+1)(n+2)/2 ∈ Θ(n²) mults due to recomputing powers. Horner is provably optimal for polynomial evaluation without preprocessing.
Paradigm: Transform & Conquer · Representation Change — re-express the polynomial in nested form to eliminate redundant work.
🔁 Bonus: LCM via GCD (Problem Reduction Demo)
Classic problem reduction: lcm(m,n) reduces to gcd(m,n) via the identity lcm(m,n) = m·n / gcd(m,n). GCD via Euclid is O(log n), so LCM also runs in O(log n). Old way: prime factorization (expensive).
Pascal's Triangle + Binomial DP DP · Combinatorics
click any cell · C(n,r) via formula, recurrence, and Pascal · (x+y)^n expansion
Selected: C(5, 2) = 10
Binomial expansion (x+y)^5
DP Recurrence (Binomial via Pascal's Identity)
function Binomial(n, r): // Θ(n·r) time, Θ(n·r) space if r == 0 or r == n: return 1 // base case return Binomial(n-1, r-1) + Binomial(n-1, r) Bottom-up DP fills the triangle row-by-row, each cell = sum of two cells above. This is the classic dynamic programming example — direct recursion repeats work exponentially; memoization/DP reduces it to Θ(n·r) ⇐ store all C(n,r) for n' ≤ n.
4 Key Identities (all visible in the triangle)
1. Pascal's Identity: C(n+1, k) = C(n, k−1) + C(n, k). Every cell = sum of two cells above. This is the recurrence.
2. Symmetry: C(n, r) = C(n, n−r). Every row mirrors around its center. (Try "symmetry" mode above.)
3. Row sum: Σⱼ C(n, j) = 2ⁿ — total number of subsets of an n-set. (Try "row sum" mode.)
4. Hockey stick: Σⱼ₌ᵣⁿ C(j, r) = C(n+1, r+1) — diagonal sums. (Try "diagonal" mode.)
Plus Vandermonde: C(m+n, r) = Σ C(m, r−k)·C(n, k), and the binomial theorem (x+y)ⁿ = Σ C(n,j)·xⁿ⁻ʲyʲ — shown live in the right panel above.
Sorted Matrix Search Variable Decrease-and-Conquer · O(n)
rows + columns sorted · start top-right · K<curr → left, K>curr → down · each step kills a row or column
Matrix · pink = current cell · green = found · grey = eliminated
Pseudocode (live)
Step narration
📊 Line Coverage — SortedMatrixSearch
Tracks step-emit count per pseudocode line. Lines 5/7 (move-left vs move-down) both fire when the key isn't trivially at the corner.
Why O(n) and not O(n²) or O(log n)?
O(n²) brute force scans every cell. O(log n) per row using binary search × n rows = O(n log n). But the corner trick beats both: starting at the top-right corner exploits the sortedness of BOTH dimensions simultaneously. Each comparison decides "eliminate this whole row" or "eliminate this whole column" — never both. After at most n + n = 2n steps either we find K or we walk off the grid ⇒ O(n).
Variable decrease-and-conquer: the "decrease" is not a fixed n−1 or n/2 — it adapts per comparison (sometimes a row drops, sometimes a column drops). Bottom-left also works (mirror direction). Top-left and bottom-right do NOT — at those corners both moves go the same way and the algorithm fails.
Other "Variable Decrease" exam algorithms: Euclid's GCD (gcd(m,n) reduces to gcd(n, m mod n)), Interpolation Search (jump proportional to key value, expected O(log log n) on uniform data).
DAG Path Counter DP · Addition Rule
label S=1 · propagate up in topological order · each node N(v) = Σ N(u) for u→v · sum at F is the answer
Graph · S=green · F=red · current=pink · count above each node
Step narration
The Addition Rule
Process vertices in topological order. Label S = 1. For every vertex v after S, set N(v) = Σ N(u) over all u → v incoming edges. The value at F is the total path count. This works because every path to v ends with exactly one incoming edge from some u, and the paths through different u's are disjoint.
Complexity: Θ(V + E) — one pass through each vertex, summing its in-edges. Far better than the brute-force "enumerate every path" which is exponential.
Lattice paths connect to Pascal's triangle! The number of paths in an m×n grid from corner to corner (only right + up moves) is C(m+n, m). Try the lattice presets — the path count at the top-right corner matches Pascal's triangle entry. This is the classic "lattice paths = binomial coefficients" identity.
Paradigm: Dynamic Programming on a DAG. Stores intermediate path counts to avoid re-enumeration. Same technique powers shortest-path counting, viability checks, and many DP problems on DAGs.
Assignments Hub A1 + A3
every question from the CIS 3490 assignments · solution reveal · link to matching program
Each Q links to the program inside this studio that drills it. Click the ▶ button below the Q to see the marking-scheme solution. Practice the linked program first, then attempt the Q on paper, then reveal.
Write & Grade DeepSeek
write the algorithm yourself · DeepSeek grades on rubric · iterative practice
DeepSeek grades on the rubric below the mode selector. After submission you'll get: marks awarded, what you got right, what you missed, and a targeted re-do hint. Use this for Section D (Algorithm Design — 15 marks).
Topological Sort DAG only · Section C
Mock 4 C19 DAG · both methods · live ordering · line-highlight pseudocode
Live ordering
—
Per-vertex state
| vertex | finish | state |
|---|
Pseudocode (live)
Both methods are Θ(V+E). DAG required — any cycle makes topological order impossible (DFS would find a back edge; Kahn would leave non-zero in-degrees stuck). Method 1 (DFS): output vertices in REVERSE order of when they finish. Method 2 (Kahn): repeatedly find vertices with in-degree 0, output, remove their outgoing edges.
Binary Trees & BST recursive
BST insertion · 4 traversals · live tree visualization · line-highlight pseudocode
Visit order
—
Pseudocode (live)
A Binary Search Tree obeys: for every node, all left descendants are smaller and all right descendants are larger. Traversal complexities are all Θ(n). BST insert is Θ(log n) avg, Θ(n) worst (skewed). Self-balancing variants (AVL, red-black) guarantee Θ(log n). Use in-order traversal on a BST to read its values in sorted order.
Backward Substitution Trainer CRITICAL · Section B
step-by-step expansion of every standard recurrence · pattern recognition for the i-th step substitution
The standard backward-sub move (memorize): Expand T(n) by substituting the recurrence repeatedly. Look for the i-th step pattern: T(n) = T(n−i) + i·W for additive (or 2ⁱ·T(n−i) + W(2ⁱ−1) for doubling). Then set i so the base case appears: i = n − 1 for n→n−1 recurrences, i = log n for n→n/2 recurrences. Finally simplify with a Σ formula (Σi = n(n+1)/2, Σi² = n(n+1)(2n+1)/6, Σ2ⁱ = 2ⁿ−1).
Nested Loop Analyzer Section B · summation method
double / triple summation derivation · step-by-step algebra · matches sorting derivations
First-move setup (cheatsheet): C(n) = Σᵢ₌₀ⁿ⁻² Σⱼ₌ᵢ₊₁ⁿ⁻¹ 1
Σ formulas to remember: Σi = n(n+1)/2 · Σi² = n(n+1)(2n+1)/6 · Σi³ = [n(n+1)/2]²
Nested for j=i+1..n-1: inner count = (n-1) − (i+1) + 1 = n−1−i
Algorithm Paradigms Quiz 30 algorithms
identify the paradigm · learn what each algorithm IS doing
The 6 paradigms (cheatsheet)
- Brute Force — directly implement definition, no optimization (e.g. closest pair, TSP, knapsack)
- Decrease & Conquer — ONE smaller instance: by constant (insertion sort), by factor (binary search), by variable (Euclid GCD)
- Divide & Conquer — MULTIPLE independent subproblems, recurse, MERGE (merge sort, D&C find max)
- Transform & Conquer — change representation, then solve (presort, Horner's, distribution counting)
- Greedy — locally optimal at each step (SJF, Prim's, Dijkstra)
- Dynamic Programming — optimal substructure + overlapping subproblems, build table (max non-adj, weighted activity)
🆘 Panic Card 2:25 PM Monday
every formula · every first-move · every edge case · one screen
DEFINITIONS
O(g): ∃ c>0,n₀≥1: f(n) ≤ c·g(n) ∀n≥n₀
Ω(g): ∃ c>0,n₀≥1: f(n) ≥ c·g(n) ∀n≥n₀
Θ(g): O(g) AND Ω(g)
c₁g ≤ f ≤ c₂g ∀n≥n₀
LIMIT TEST
lim T/g = 0 → O, not Ω (T slower) lim T/g = c>0 → Θ (same) lim T/g = ∞ → Ω, not O (T faster) a^(log_b n) = n^(log_b a) log(n!) = Θ(n log n) [Stirling]
HIERARCHY (slow → fast)
1 ≺ log log n ≺ log n ≺ √n ≺ n ≺ n log n ≺ n² ≺ n³ ≺ 2ⁿ ≺ 3ⁿ ≺ n! ≺ nⁿ
SUMMATIONS
Σi = n(n+1)/2 Θ(n²) Σi² = n(n+1)(2n+1)/6 Θ(n³) Σi³ = [n(n+1)/2]² Θ(n⁴) Σaⁱ = (a^(n+1)-1)/(a-1) Θ(aⁿ) Σ√i ≈ (2/3)n^(3/2) Θ(n^1.5)
RECURRENCES (memorize)
T(n-1)+1 → n Θ(n) T(n-1)+n → n(n+1)/2 Θ(n²) 2T(n-1)+1 → 2ⁿ-1 Θ(2ⁿ) T(n/2)+1 → log₂n Θ(log n) T(n/2)+n → ~2n Θ(n) T(n/2)+log n → (log n)²/2 Θ(log²n) 2T(n/2)+1 → 2n-1 Θ(n) 2T(n/2)+n → n log₂n Θ(n log n) 2T(n-2)+1 → 2^(n/2) Θ(2^(n/2)) 3T(n/3)+n → n log n Θ(n log n) 4T(n/2)+n² → n² log n M.Case 2
MASTER THEOREM
T(n) = a·T(n/b) + f(n) k = n^(log_b a) Case 1: f = O(k^(1-ε)) → Θ(k) Case 2: f = Θ(k) → Θ(k log n) Case 3: f = Ω(k^(1+ε))+reg → Θ(f) Merge sort: 2T(n/2)+n → k=n, f=n → Case 2 → Θ(n log n)
SORTING
Insertion: best Θ(n), worst Θ(n²) C_worst = n(n-1)/2. STABLE. ONLINE. swaps = # inversions Selection: Θ(n²) ALWAYS Exactly n-1 swaps. NOT stable. Best when writes expensive. Bubble: best Θ(n) w/ flag, worst Θ(n²) Stable. Merge: Θ(n log n) ALWAYS T=2T(n/2)+n → Case 2. Stable. Θ(n) extra space.
GRAPHS
DFS: stack/recursion. Tree+BACK edges.
Back edge → CYCLE detected.
Θ(V+E) on adj list.
BFS: queue. Tree+CROSS edges.
Shortest path (unweighted).
Θ(V+E) on adj list.
Topo sort: DAG only. Θ(V+E).
Method 1: DFS, reverse finish order.
Method 2: remove in-degree-0 vertices.
Prim's MST: Θ(V²) array, Θ((V+E)logV) heap.
V-1 edges. Tie: alphabetical NEW vertex.
BRUTE FORCE
Closest Pair: C(n,2). dx²+dy². Θ(n²). D&C: O(n log n). Convex Hull: a=yⱼ-yᵢ, b=xᵢ-xⱼ, c=xᵢyⱼ-yᵢxⱼ. val=axₖ+byₖ-c. Hull iff same sign for ALL k. O(n³). TSP: (n-1)!/2 tours. O(n!). NP-Hard. Knapsack: 2ⁿ subsets. NP-Hard. Assignment: O(n³) Hungarian. NOT NP-Hard! String match: O(nm). Avg Θ(n).
FIRST-MOVE SETUPS
Prove O: "Need c>0, n₀≥1 s.t. f(n) ≤ c·g(n) for all n ≥ n₀." Limits: "lim(n→∞) f(n)/g(n)." Backward sub: "T(n)=T(n-1)+W = T(n-i)+iW. At i=n: T(0)+nW." Master: "a=__,b=__,f=__. k=n^(log_b a)=__. Compare→Case __." Insertion worst: "C(n)=Σᵢ₌₁ⁿ⁻¹ i = n(n-1)/2" DP non-adj: "M(0)=0, M(1)=A[1]. M(i)=max(M(i-1), A[i]+M(i-2))."
YOU NEED 38/50.
Section A (10) target: 7-8 · Section B (15) target: 10-12 · Section C (10) target: 7-8 · Section D (15) target: 8-10
First line correct = partial marks. Use this. You have the time. Execute the plan.