Problem Description
Given a weighted tree (represented with an array where each entry indicates the parent and weight of the edge connecting a node to its parent), choose a subset of edges such that no two selected edges are adjacent (i.e. share a common node) and the total sum of weights is maximized. Note that you may choose no edge at all if that yields a better result.
Key Insights
- The tree is rooted at node 0 and every edge can be thought of as connecting a parent and a child.
- Two edges are adjacent if they share a node; therefore, if you choose an edge connecting node u to v, neither any other edge incident to u nor any edge incident to v can be chosen.
- A dynamic programming solution on trees (DFS) is natural. Define two states for each node:
- A "free" state where the edge from its parent is NOT used, so the node is free to choose one outgoing edge (to one of its children).
- A "blocked" state where the parent's edge to this node is chosen, so the node cannot use any of its outgoing edges.
- The recurrence for a node in the free state is the maximum of either not choosing any outgoing edge (taking the sum over children in a free state) or choosing exactly one child edge (which adds the weight of that edge and forces that child into a blocked state, while others remain free).
- These state transitions allow combining results from subtrees while enforcing the “no adjacent edges” rule.
Space and Time Complexity
Time Complexity: O(n), where n is the number of nodes. Each node is processed once and the children are scanned in O(deg(node)) time. Space Complexity: O(n) for storing the tree structure and the recursion stack.
Solution
We use DFS on the tree and compute two DP values for each node:
- dp[node][free]: Maximum sum obtainable from the subtree rooted at node when the edge connecting it to its parent is not selected. Here, the node is free to optionally pick one of its outgoing edges.
- dp[node][blocked]: Maximum result when the node is blocked because the parent's edge was chosen. In this case, the node cannot pick any outgoing edge.
For a node in the free state, we:
- Assume initially that no outgoing edge is selected; summing over all children in the free state.
- Then, for each child, consider “switching” from free to taking that edge – which contributes weight(child) + dp[child][blocked] instead of dp[child][free]. Only one such edge can be chosen because choosing one edge makes the parent node incident to a chosen edge and invalidates any further picks from that node.
Thus, letting children = all direct children of the node and sum_free = Σ dp[child][free] for each child, we have: dp[node][free] = sum_free + max(0, max over each child { dp[child][blocked] + weight(child) - dp[child][free] }).
If the node is blocked, then: dp[node][blocked] = sum_free since no outgoing edge may be chosen.
The final answer is dp[root][free] since the root (node 0) is free (its non-existent parent did not contribute an edge).