Problem Description
Given an undirected tree with n nodes (numbered from 0 to n-1) and a list of weighted edges, remove zero or more edges so that for every node, the degree (number of incident edges) is at most k. The goal is to maximize the sum of weights of the remaining edges.
Key Insights
- The tree structure implies there is no cycle so we can use DFS for dynamic programming.
- Each node is constrained by a maximum number (k) of incident edges; if more edges exist, we must choose which ones to keep.
- A greedy/dynamic programming approach works by, for each node, deciding which child edges yield the maximum improvement to the total sum while respecting degree limits.
- The problem can be thought of as a kind of tree knapSack: for each node, when combining contributions from children, we choose up to k (or k-1 if an edge to the parent is used) edges that bring extra benefit relative to skipping them.
- Using two DP states per node (one when the parent's connection is not counted and one when it is) helps manage the varying available degree at each node.
Space and Time Complexity
Time Complexity: O(n log n) in worst-case due to sorting improvements at each node (the summation over all children across nodes is O(n)). Space Complexity: O(n), due to recursion stack and the DP array for each node.
Solution
We solve the problem with a DFS-based dynamic programming approach.
- Represent the tree using an adjacency list.
- For each node, define two DP values:
- dp[node][0] represents the maximum sum in the subtree rooted at this node when the edge from its parent is NOT considered as “using up” one of its k allowed connections (i.e. the node can use up to k edges among its children).
- dp[node][1] represents the maximum sum in the subtree when the edge from its parent is already taken, so the node can use at most k-1 child connections.
- For every node, recursively calculate contributions from its children. For each child, there is a potential “gain” if we choose to include the edge (child edge weight plus dp[child][1]) over skipping the edge (dp[child][0]).
- Collect all positive gains from children. Then, sort them in descending order. Add as many positive gains as allowed (up to k for dp[node][0] and up to k-1 for dp[node][1]).
- Finally, dp[0][0] (if we take 0 as the root which has no parent) gives us the maximum sum.
Important details include ensuring that we do not count an edge twice (once for each of its two nodes) and carefully merging the gains while respecting the constraints.