Dynamic Programming on Trees
When the subproblems of a dynamic program are rooted subtrees, a single post-order DFS solves the whole thing in : each node combines the already-computed answers of its children. We meet the archetype — maximum-weight independent set on a tree — then the "path through a node" pattern behind tree diameter and maximum path sum, and finally rerooting, which computes a per-node answer for every node as root in with two passes.
╌╌╌╌
Dynamic programming works whenever a problem decomposes into overlapping subproblems ordered so that each can be solved from smaller ones already in hand. On a sequence the natural subproblems are prefixes; on an interval they are subintervals. On a tree the natural subproblems are rooted subtrees, and the ordering that makes them solvable is the post-order traversal, which visits every node only after all of its children. Root the tree anywhere, define an answer for the subtree hanging below each node , and a single depth-first sweep fills the entire table.
The defining feature of these problems is that the recurrence is local: the answer at depends only on the answers at 's children,
never on grandchildren directly and never on the rest of the tree. Because the DFS touches each node and each edge exactly once and does work per child, the whole computation runs in time for a tree on nodes.1 The work is in choosing the state: what must remember about the subtree so that a parent can combine children without re-descending into them. This is the usual optimal-substructure question, specialized to subtrees.
The archetype: maximum-weight independent set
Let each node of a tree carry a weight . An independent set is a set of nodes no two of which are adjacent; we want one of maximum total weight. On a general graph this is NP-hard, but on a tree dynamic programming solves it in linear time, the canonical illustration of the whole technique.2
The idea is to make the state record whether itself is used, because that is the one fact a parent needs in order to decide about itself. Define, for the subtree rooted at , two values:
- , the best independent set of 's subtree in which is not taken;
- , the best one in which is taken.
If is not taken, each child is free to be taken or not, so we keep the better of its two options. If is taken, no child may be taken, so each child must contribute its :
The base case falls out for free: a leaf has no children, so and . The answer for the whole tree is . This is House Robber III, where weights are the money in each house and the adjacency constraint forbids robbing a parent and its child on the same night.
- 1if then
- 2return
- 3taken
- 4excluded
- 5for each child of do
- 6
- 7child free
- 8child forbidden
- 9return
The procedure visits each node once and spends per child, hence total. The state, taken vs. not taken, is the part worth remembering: a single extra bit per node turns an intractable graph problem into a linear-time tree sweep.3
To see the post-order fill in full, take the tree in the figure with root (weight ), children (weight ) and (weight ), then leaves (weights ) under and leaf (weight ) under . Post-order visits the leaves first, then , then , then . Each row is the pair :
| node | children | |||
|---|---|---|---|---|
| — | ||||
| — | ||||
| — | ||||
The answer is , achieved by taking . Taking forbids and , so we descend into and , each of which skips its own node and is free to take the leaves below: that selects , , , , with weights — the shaded set in the figure. Every value in the table is read from children already computed, never recomputed — that single-pass reuse is what makes the sweep linear.
Paths through a node: diameter and maximum path sum
A second pattern arises when the quantity we care about is a path, not a set. The diameter of a tree is the number of edges on its longest path; the maximum path sum (where nodes carry values, possibly negative) is the largest total along any path. Neither is a clean subtree quantity, because the optimal path may bend at some node, descending into two different children.
The resolution is the signature move of tree DP on paths. At each node , let be the best downward path that starts at and goes into a single subtree. A child extends to . The best path that bends at combines its two best children:
for the two children with the largest downward values. The distinction below is the source of the classic bug:
- 1if then
- 2return
- 3drop negative branches
- 4
- 5bend here: both sides
- 6returnextendable: one side
For Binary Tree Maximum Path Sum the prunes branches that would only hurt the total; the global records the best bend seen anywhere. On the tree in the figure — root with left leaf and right child whose children are leaves and — the post-order pass runs as follows. The leaves , , each return their own value (no children), and update with themselves. At node : , , so the bent path is , which becomes the new ; it returns upward only . At the root : , , and its bent path is , so stays . The negative root could not improve the answer, and the guards ensured no negative branch was added into a sum. The final answer is , the two-child bend at — a path that the node correctly updated the global with but did not return.
For Diameter of Binary Tree the same skeleton applies with edge counts in place of values: and the diameter is the largest over all nodes . Both run in : one post-order pass, per node.
Rerooting: an answer for every root in
The hardest variant asks for a quantity computed with each node in turn as the
root: for every node , say, the sum of distances from to all
other nodes. Re-running an DFS from each of the roots costs .
Rerooting (also called the all-roots
or re-root
technique) computes all
answers in total, with two DFS passes: one down, one up.4
Take Sum of Distances in Tree. Fix an arbitrary root and let be the number of nodes in 's subtree and the sum of distances from to every node inside its own subtree. A post-order pass computes both, since a child at distance contributes (every node under is one edge farther from than from ):
That gives the true global answer only at the root, where the subtree is the whole tree: . The second pass pushes the answer from a parent to each child in . Moving the root from to an adjacent child , the nodes on 's side each get one closer (distance drops by ) and the remaining nodes each get one farther:
Subtract the subtree's contribution, add the rest: the entire adjustment is a single formula, so the down-pass plus the up-pass together are .
On the five-node tree above (root with children ; then under and under ), the down-pass fixes . The up-pass then propagates outward, each step a single subtract-add. Moving to : its subtree has nodes, so . From to its child (): . By symmetry and . Every value matches a direct BFS from that node, but the whole sweep is linear.
A related linear-time tree DP is Distribute Coins in Binary Tree: each node returns to its parent the net coins it must send up or pull down, the signed excess summed over its subtree, and the total number of moves is the sum of absolute flows along every edge, accumulated in one post-order pass. Same shape: a local return value, a global accumulator, time.
From trees back to hard graphs
Tree DP is a special case of a deeper result. The reason maximum-weight independent
set is linear on trees but NP-hard on general graphs is treewidth: a tree has
treewidth , and Courcelle's theorem (Courcelle, 1990) says that any graph
property expressible in monadic second-order logic — independent set, dominating
set, Hamiltonicity, -coloring for fixed — is decidable in linear time on
graphs of bounded treewidth, by a dynamic program over a tree decomposition.
The post-order combine in this lesson is the treewidth- instance of that DP; on
a width- decomposition each bag
of vertices plays the role a
single node plays here, and the state grows to roughly per bag, so the
runtime is . This is why bounded treewidth — the graph is
nearly a tree — is such a useful property of an instance.5
Rerooting, the two-pass all-roots
technique, is the tree analog of an idea that
recurs across algorithms: compute one anchored answer, then transfer it along edges
with a cheap difference. The same accounting drives the all-pairs flavor of many
tree problems and appears in Skiena's treatment of tree DP and in competitive
references under names like in-and-out DP
or up-and-down DP
. It also connects to
centroid decomposition: both
exploit that a tree, unlike a general graph, has a balanced recursive structure that
turns an apparent over all pairs of nodes into or .
A modern practical descendant is belief propagation (Pearl, 1988) on graphical
models: on a tree-structured probabilistic model, the sum-product message-passing
algorithm computes exact marginals in one up-pass and one down-pass — structurally
identical to rerooting, with / over children replaced by products of
messages. The independent-set recurrence here is the hard-core model
special case,
and the reason inference is exact on trees but only approximate (loopy BP
) on
general graphs is, again, that trees have no cycles to double-count.
Takeaways
- On a tree, the natural DP subproblems are rooted subtrees, solved by a single post-order DFS that combines each node's children in , hence overall, since every node and edge is processed once.
- The state must capture just what a parent needs. For maximum-weight independent set (House Robber III) that is one bit, taken vs. not taken: and .
- The path-through-a-node pattern (diameter, max path sum) returns one thing and updates another: return the single best downward extension to the parent, but update a global max with the two-child bent path, never returning the bent path.
- Rerooting computes a per-root answer for all nodes in via two
passes: a down-pass fixes the root's answer from subtree aggregates, an up-pass
transfers it edge-by-edge with a
subtract my subtree, add the rest
adjustment. - The recurring design questions are always the same: what does a node return to its parent, and what aggregate must the subtree cache so the combine stays .
Footnotes
- Erickson, Ch. — Dynamic Programming (trees): subtree subproblems solved bottom-up by post-order traversal in . ↩
- Skiena, § — Dynamic Programming on Trees: maximum independent set on trees as the linear-time archetype of tree DP. ↩
- CLRS, Ch. 15 — Dynamic Programming: optimal substructure and the combination of subproblem solutions, instantiated here on rooted subtrees. ↩
- Skiena, § — Dynamic Programming on Trees: the all-roots / rerooting technique computing every node's answer in with two DFS passes. ↩
- Courcelle (1990),
The monadic second-order logic of graphs I
: any MSO-expressible graph property is linear-time decidable on graphs of bounded treewidth via DP over a tree decomposition; tree DP is the treewidth- case. See also Pearl (1988), Probabilistic Reasoning in Intelligent Systems, for the sum-product / belief-propagation analog on tree-structured models. ↩
╌╌ END ╌╌