Tree Coloring
From Two States to Many
Every problem in this chapter so far had two states per node: take or skip, in cover or not, matched or unmatched. Coloring generalizes this to \(k\) states.
A proper \(k\)-coloring assigns one of \(k\) colors to each node so that no two adjacent nodes share the same color. The question: how many valid \(k\)-colorings does a tree have?
Trees Are Always 2-Colorable
First, the existence question. Can every tree be 2-colored? Yes — trees are bipartite. Run BFS from the root, alternating colors at each level. Since trees have no cycles, you'll never hit a conflict.
This is a well-known fact, but it connects directly to this chapter's theme: bipartiteness is the "coloring" version of the include-exclude structure. At each node, you choose one of two states. Adjacency constraints restrict which states neighbors can share.

Counting: The Closed-Form Formula
How many valid \(k\)-colorings does a tree with \(n\) nodes have?
Root the tree at any node. The root has \(k\) choices. Every other node must differ from its parent, so it has \(k - 1\) choices. Since the tree structure means each non-root node has exactly one parent, and subtrees are independent:
That's it. No DP needed for this version.
Example: The path 1-2-3 with \(k = 3\) colors. Root at node 1: 3 choices. Node 2: must differ from 1, so 2 choices. Node 3: must differ from 2, so 2 choices. Total: \(3 \times 2 \times 2 = 12\).
Verification for \(k = 2\): A path of 3 nodes with 2 colors. Root gets 2 choices. Each subsequent node gets 1 choice. Total: \(2 \times 1 \times 1 = 2\). These are: (R, B, R) and (B, R, B). Correct.
Why the formula works: In a tree, the constraint graph is a tree itself. Each node's color is constrained only by its parent. No cycles means no additional constraints beyond parent-child.
When the Formula Isn't Enough
The formula \(k \cdot (k-1)^{n-1}\) assumes every "adjacent nodes must differ" constraint. But what if you have mixed constraints?
- Some edges require "must differ" (standard coloring)
- Some edges require "must agree" (same color)
- Some nodes are pre-colored
Now you need actual DP. And this is where coloring connects to the include-exclude framework.
The DP Approach
Define \(\text{dp}[\text{node}][c]\) = number of valid colorings of this node's subtree when this node is assigned color \(c\).
Leaf node: \(\text{dp}[\text{leaf}][c] = 1\) for every color \(c\).
Internal node with "must differ" constraint: For each color \(c\) assigned to this node, each child can take any color except \(c\):
The total for the tree is \(\sum_{c} \text{dp}[\text{root}][c]\).
Full Trace
Using \(k = 3\) colors (call them 0, 1, 2). Process bottom-up.
Leaves (nodes 3, 4, 5): dp = [1, 1, 1] for each.
Node 2 (children: 4, 5):
For each color \(c\) of node 2, child 4 can be any color except \(c\), and child 5 can be any color except \(c\).
| Color of node 2 | Valid colors for child 4 | Count from child 4 | Valid colors for child 5 | Count from child 5 | dp[2][c] |
|---|---|---|---|---|---|
| 0 | {1, 2} | 1 + 1 = 2 | {1, 2} | 2 | 2 * 2 = 4 |
| 1 | {0, 2} | 1 + 1 = 2 | {0, 2} | 2 | 4 |
| 2 | {0, 1} | 1 + 1 = 2 | {0, 1} | 2 | 4 |
So dp[2] = [4, 4, 4].
Node 1 (children: 2, 3):
| Color of node 1 | Valid from child 2 | Valid from child 3 | dp[1][c] |
|---|---|---|---|
| 0 | dp[2][1] + dp[2][2] = 4 + 4 = 8 | dp[3][1] + dp[3][2] = 1 + 1 = 2 | 8 * 2 = 16 |
| 1 | dp[2][0] + dp[2][2] = 4 + 4 = 8 | dp[3][0] + dp[3][2] = 1 + 1 = 2 | 16 |
| 2 | dp[2][0] + dp[2][1] = 4 + 4 = 8 | dp[3][0] + dp[3][1] = 1 + 1 = 2 | 16 |
Total: \(16 + 16 + 16 = 48\).
Formula check: \(k \cdot (k-1)^{n-1} = 3 \cdot 2^4 = 3 \cdot 16 = 48\). Matches.
Constraint Propagation
The DP above is doing constraint propagation — the color choice at a parent restricts what's available at each child. In the standard "must differ" case, the restriction is symmetric and leads to the clean formula.
But consider a mixed scenario: edge (1,2) requires "must agree" while all other edges require "must differ." Now node 2 MUST have the same color as node 1. The formula breaks — you need the DP.
This is the same structure as include-exclude, just with more states:
| Framework | States per node | Constraint |
|---|---|---|
| Independent Set | {skip, take} | take → children skip |
| Vertex Cover | {out, in} | out → children in |
| \(k\)-Coloring | {color 0, color 1, ..., color \(k{-}1\)} | color \(c\) → children not \(c\) |
Coloring IS include-exclude with \(k\) states instead of 2. The recurrence has the same product-over-children shape. The only difference is the number of options at each node.
The Code
For the general DP (works with any constraint pattern):
vector<long long> solve(TreeNode* root, int numColors) {
vector<long long> colorCount(numColors, 1);
if (!root) return vector<long long>(numColors, 1);
auto leftCounts = root->left ? solve(root->left, numColors)
: vector<long long>(numColors, 1);
auto rightCounts = root->right ? solve(root->right, numColors)
: vector<long long>(numColors, 1);
long long totalLeft = 0;
long long totalRight = 0;
for (int c = 0; c < numColors; c++) {
totalLeft += leftCounts[c];
totalRight += rightCounts[c];
}
for (int c = 0; c < numColors; c++) {
long long validLeft = totalLeft - leftCounts[c];
long long validRight = totalRight - rightCounts[c];
colorCount[c] = validLeft * validRight;
}
return colorCount;
}
long long countColorings(TreeNode* root, int numColors) {
if (!root) return 0;
auto counts = solve(root, numColors);
long long total = 0;
for (long long c : counts) total += c;
return total;
}
Complexity: \(O(n \cdot k)\) time, \(O(h \cdot k)\) space.
The Chromatic Polynomial
What you just computed is actually a famous object: the chromatic polynomial \(P(T, k)\) of a tree \(T\). For any tree with \(n\) nodes, \(P(T, k) = k \cdot (k-1)^{n-1}\). This polynomial tells you the number of valid \(k\)-colorings for any positive integer \(k\).
Plug in \(k = 1\): \(1 \cdot 0^{n-1} = 0\) (can't color any tree with one color if \(n > 1\)). Plug in \(k = 2\): \(2 \cdot 1^{n-1} = 2\) (exactly two 2-colorings for any tree). These match intuition.
For general graphs, the chromatic polynomial is much harder to compute. But for trees, the lack of cycles makes everything factor cleanly.
Try It
Predict before running: How many valid 2-colorings does a 5-node tree have? \(2 \cdot 1^4 = 2\). Always just 2 — swap the two colors.
Challenge: A tree has 10 nodes. How many valid 4-colorings? \(4 \cdot 3^9 = 4 \cdot 19683 = 78732\).
Challenge 2: If one node is pre-colored (say the root must be red), how does the formula change? The root no longer has \(k\) choices — it has 1. So the count becomes \((k-1)^{n-1}\).
Edge Cases to Watch For
- \(k = 1\) with \(n > 1\): The formula gives \(1 \times 0^{n-1} = 0\), which is correct (two adjacent nodes can't share one color). But if your code computes \(0^0\) for the \(n=1\) subcase, some languages return unexpected results — guard this explicitly.
- Pre-colored node: If one node is fixed to a specific color, the root has 1 choice instead of \(k\). The count becomes \((k-1)^{n-1}\). Forgetting to adjust the root factor is a common bug when constraints add fixed colors.
- Integer overflow in the formula: \(k \cdot (k-1)^{n-1}\) grows exponentially. For \(n = 20\) and \(k = 10\), the result exceeds \(10^{19}\), overflowing
long long. Use modular arithmetic if the problem requires it.
Problems
| Problem | Link | Difficulty |
|---|---|---|
| LC 886 — Possible Bipartition | leetcode.com/problems/possible-bipartition | Medium |
| LC 785 — Is Graph Bipartite? | leetcode.com/problems/is-graph-bipartite | Medium |
| CF 902B — Coloring a Tree | codeforces.com/problemset/problem/902/B | Easy |