3.7.14Algorithm Paradigms

DP problems — rod cutting, egg drop, DP on trees

2,368 words11 min readdifficulty · medium

1. Rod Cutting

Deriving the recurrence from scratch

WHAT we want: r(n)r(n) = best revenue obtainable from a rod of length nn.

HOW to think recursively: the leftmost piece has some length ii (where 1in1 \le i \le n). We earn p[i]p[i] for it, and the remaining rod of length nin-i is a fresh, identical subproblem.

So we try every first-piece length and keep the best:

r(n)=max1in(p[i]+r(ni)),r(0)=0r(n) = \max_{1 \le i \le n}\big(\, p[i] + r(n-i)\,\big), \qquad r(0)=0

WHY this is correct: every possible cutting of the rod has some leftmost piece. By looping ii over all possible leftmost lengths, we are guaranteed to consider every arrangement. Choosing the max gives the optimum — this is the optimal substructure: an optimal solution to the whole contains optimal solutions to the parts.

def rod_cut(p, n):          # p[i] = price of length i, p[0]=0
    r = [0]*(n+1)
    cut = [0]*(n+1)         # to reconstruct
    for j in range(1, n+1):
        best = float('-inf')
        for i in range(1, j+1):
            if p[i] + r[j-i] > best:
                best = p[i] + r[j-i]
                cut[j] = i
        r[j] = best
    return r[n], cut

2. Egg Drop

Deriving the recurrence

Let D(e,f)D(e,f) = minimum worst-case drops with ee eggs and ff floors.

HOW: drop an egg from some floor xx (counting from the bottom of the current range). Two cases, and we must survive the worst:

  • Egg breaks → threshold is at or below xx, in the x1x-1 floors below. Eggs drop to e1e-1. Cost: D(e1,x1)D(e-1,\, x-1).
  • Egg survives → threshold is above xx, in the fxf-x floors above. Eggs stay ee. Cost: D(e,fx)D(e,\, f-x).

Worst case = the max of the two (adversary picks the worse outcome). We pay 1 for this drop, then choose xx to minimize the worst case:

D(e,f)=1+min1xfmax(D(e1,x1),  D(e,fx))D(e,f)=1+\min_{1\le x\le f}\,\max\big(D(e-1,x-1),\;D(e,f-x)\big)

Base cases (WHY they hold):

  • D(e,0)=0D(e,0)=0 — zero floors, nothing to test.
  • D(e,1)=1D(e,1)=1 — one floor, one drop confirms.
  • D(1,f)=fD(1,f)=f — one egg forces linear scan.
def egg_drop(eggs, floors):
    D = [[0]*(floors+1) for _ in range(eggs+1)]
    for f in range(1, floors+1):
        D[1][f] = f
    for e in range(2, eggs+1):
        for f in range(1, floors+1):
            best = float('inf')
            for x in range(1, f+1):
                worst = 1 + max(D[e-1][x-1], D[e][f-x])
                best = min(best, worst)
            D[e][f] = best
    return D[eggs][floors]

3. DP on Trees

Deriving the states

WHAT we need: for each node, two answers because the parent's choice depends on whether we are included.

  • f(v,1)f(v,1) = best weight in vv's subtree with vv included.
  • f(v,0)f(v,0) = best weight in vv's subtree with vv excluded.

HOW to combine children cc:

  • If vv is included, no child may be included: f(v,1)=wv+cchildrenf(c,0)f(v,1)=w_v+\sum_{c\in\text{children}} f(c,0)
  • If vv is excluded, each child is free to be included or not — take the best: f(v,0)=cchildrenmax(f(c,1),f(c,0))f(v,0)=\sum_{c\in\text{children}}\max\big(f(c,1),\,f(c,0)\big)

WHY correct: subtrees are disjoint, so their best values simply add. The adjacency constraint only couples a parent with its direct children — exactly what the two states encode.

Answer = max(f(root,1),f(root,0))\max(f(\text{root},1),\,f(\text{root},0)). Time O(n)O(n) (each edge processed once).

def mwis_tree(adj, w, root=0):
    # adj: adjacency list, w: weights, tree rooted at `root`
    f0 = [0]*len(w); f1 = [0]*len(w)
    def dfs(v, parent):
        f1[v] = w[v]; f0[v] = 0
        for c in adj[v]:
            if c != parent:
                dfs(c, v)
                f1[v] += f0[c]
                f0[v] += max(f0[c], f1[c])
    dfs(root, -1)
    return max(f0[root], f1[root])
Figure — DP problems — rod cutting, egg drop, DP on trees

Flashcards

Rod cutting recurrence
r(n)=max1in(p[i]+r(ni))r(n)=\max_{1\le i\le n}(p[i]+r(n-i)), r(0)=0r(0)=0
Rod cutting time complexity
O(n2)O(n^2) with O(n)O(n) space
What subproblem does rod cutting recurse on?
a shorter rod (the part after the leftmost cut)
Egg drop recurrence
D(e,f)=1+minxmax(D(e1,x1),D(e,fx))D(e,f)=1+\min_x \max(D(e-1,x-1),\,D(e,f-x))
Why max inside egg drop?
adversary forces the worst of {egg breaks, egg survives}
Egg drop base cases
D(e,0)=0D(e,0)=0, D(e,1)=1D(e,1)=1, D(1,f)=fD(1,f)=f
Egg drop with 2 eggs, 10 floors?
4 drops
Why isn't binary search optimal for egg drop?
a broken egg is lost forever; only optimal with unlimited eggs
DP-on-tree MWIS states
f(v,1)f(v,1)=best with v included, f(v,0)f(v,0)=best with v excluded
f(v,1)f(v,1) formula
wv+cf(c,0)w_v+\sum_c f(c,0) (children must be excluded)
f(v,0)f(v,0) formula
cmax(f(c,1),f(c,0))\sum_c \max(f(c,1),f(c,0))
DP on tree time complexity
O(n)O(n) — each node/edge processed once in DFS
Why does DP work cleanly on trees?
no cycles → each subtree is an independent subproblem
Egg drop dual recurrence (floors from drops)
F(e,d)=F(e1,d1)+F(e,d1)+1F(e,d)=F(e-1,d-1)+F(e,d-1)+1

Recall Feynman: explain to a 12-year-old

Rod cutting: You have a long chocolate bar and a price list for pieces. You ask: "What's the best money if I break off a small piece on the left first?" Try every possible first piece, then ask the same question about the leftover bar. The computer remembers the answer for each length so it never re-asks.

Egg drop: You have 2 special eggs and want to find the highest floor you can drop from without breaking. If you guess a floor and it breaks, you must carefully test below it (egg gone!). If it survives, you can try higher. You plan so that even on your unluckiest day you find the floor in as few drops as possible.

DP on trees: Imagine a family tree where each person has a value, but a parent and child can't both be picked (they'd argue!). You start from the youngest kids, figure out the best for each little family, then pass two notes up to each parent: "best if you join" and "best if you sit out." The parent adds up the notes. The top of the tree gives the final best.

Connections

  • Dynamic Programming — optimal substructure + overlapping subproblems
  • Recursion and Memoization — top-down version of all three
  • Greedy Algorithms — contrast: greedy fails MWIS & egg drop
  • Binary Search — speeds up egg-drop's minx\min_x and clarifies why it alone fails
  • Tree Traversal (DFS) — post-order is the engine of tree DP
  • Knapsack Problem — rod cutting is unbounded knapsack with length=weight=price-index

Concept Map

core idea

avoids

DP turns

instance

instance

instance

subproblem is

recurrence

based on

subproblem is

subproblem is

combine children to answer

complexity

Dynamic Programming

Find recursive subproblem structure

Brute force recomputation

Exponential into polynomial

Rod Cutting

Egg Drop

DP on Trees

Shorter rod

r n = max p i + r n-i

Optimal substructure

Fewer eggs, fewer floors

A subtree

O of n squared time

Hinglish (regional understanding)

Intuition Hinglish mein samjho

Dekho, teeno problems ka core idea ek hi hai: bade problem ko chote identical subproblems me todo, aur har subproblem ka answer ek baar nikaal ke store kar lo — phir dobara mat compute karo. Yahi DP ka asli jaadu hai, exponential se polynomial.

Rod cutting me rod ko pieces me kaatke max paisa kamana hai. Trick: leftmost piece ki length ii try karo (1 se nn tak), uska price lo, aur baaki nin-i length ka rod ek naya same problem ban jata hai — uska best answer pehle se nikla hua hai. Formula: r(n)=max(p[i]+r(ni))r(n)=\max(p[i]+r(n-i)). Bas saare ii try karke max le lo.

Egg drop thoda dimaag-ghumaau hai. ee ande aur ff floors hain, worst case me minimum drops chahiye. Kisi floor xx se drop karo: agar anda toot gaya to neeche x1x-1 floors me threshold hai aur ek anda kam — D(e1,x1)D(e-1,x-1). Agar bach gaya to upar fxf-x floors me, ande wahi — D(e,fx)D(e,f-x). Adversary worst case dega isliye in dono ka max lo, aur phir best xx chunne ke liye min. Yaad rakho: binary search yahan optimal nahi, kyunki ek toota anda hamesha ke liye gaya — info lost!

DP on trees sabse clean hai. Tree me cycle nahi hota, isliye har subtree independent subproblem hai. DFS se neeche (leaves) se shuru karo. Har node do answer bhejta hai parent ko: "agar main include hua" (f(v,1)=wv+f(c,0)f(v,1)=w_v+\sum f(c,0), children exclude) aur "agar main exclude hua" (f(v,0)=max(f(c,1),f(c,0))f(v,0)=\sum \max(f(c,1),f(c,0))). Bas O(n)O(n) time. Greedy yahan fail hoti hai — heavy node uthane se uske padosi block ho jaate hain. Mantra yaad rakho: "Rod LEFT, Egg WORST, Tree TWO notes."

Go deeper — visual, from zero

Test yourself — Algorithm Paradigms

Connections