DP on Trees - Introduction
Authors: Michael Cao, Benjamin Qi
Using subtrees as subproblems.
Focus Problem – try your best to solve this problem before continuing!
Tutorial
Resources | ||||
---|---|---|---|---|
CF | ||||
Philippines | bad code format |
Pro Tip
Don't just dive into trying to figure out a DP state and transitions -- make some observations if you don't see any obvious DP solution! Also, sometimes a greedy strategy suffices in place of DP.
Solution - Tree Matching
Solution 1
In this problem, we're asked to find the maximum matching of a tree, or the largest set of edges such that no two edges share an endpoint. Let's use DP on trees to do this.
Root the tree at node , allowing us to define the subtree of each node.
Let represent the maximum matching of the subtree of such that we don't take any edges leading to some child of . Similarly, let represent the maximum matching of the subtree of such that we take one edge leading into a child of . Note that we can't take more than one edge leading to a child, because then two edges would share an endpoint.
Taking No Edges
Since we will take no edges to a child of , the children vertices of can all take an edge to some child, or not. Additionally, observe that the children of taking an edge to a child will not prevent other children of from doing the same. In other words, all of the children are independent. So, the transitions are:
Taking One Edge
The case where we take one child edge of is a bit trickier. Let's assume the edge we take is , where . Then, to calculate for the fixed :
In other words, we take the edge , but we can't take any children of in the matching, so we add . Then, to deal with the other children, we add:
Fortunately, since we've calculated already, this expression simplifies to:
Overall, to calculate the transitions for over all possible children :
Warning!
Loop through the children of twice to calculate and separately! You need to know to calculate .
C++
#include <bits/stdc++.h>using namespace std;using ll = long long;using vi = vector<int>;#define pb push_back#define rsz resize#define all(x) begin(x), end(x)#define sz(x) (int)(x).size()using pi = pair<int, int>;#define f first
Java
import java.io.*;import java.util.*;public class TreeMatching {static ArrayList<Integer> adj[];static int dp[][];static void dfs(int v, int p) {for (int to : adj[v]) {if (to != p) {dfs(to, v);
Solution 2 - Greedy
Just keep matching a leaf with the only vertex adjacent to it while possible.
C++
int n;vi adj[MX];bool done[MX];int ans = 0;void dfs(int pre, int cur) {for (int i : adj[cur]) {if (i != pre) {dfs(cur, i);if (!done[i] && !done[cur]) done[cur] = done[i] = 1, ans++;
Java
import java.io.*;import java.util.*;public class TreeMatching {static ArrayList<Integer> adj[];static int N;static boolean done[];static int ans = 0;static void dfs(int v, int p) {for (int to : adj[v]) {
Problems
Easier
Status | Source | Problem Name | Difficulty | Tags | |
---|---|---|---|---|---|
AC | Easy | Show TagsDP, Tree | |||
Gold | Easy | Show TagsDP, Tree | |||
CF | Normal | Show TagsDP, Tree | |||
Baltic OI | Normal | Show TagsGreedy, Tree | |||
CF | Normal | Show TagsGreedy, Tree | |||
POI | Normal | Show TagsTree | |||
CF | Normal | Show TagsDP, Tree | |||
CF | Normal | Show TagsDP, Tree | |||
Gold | Hard | Show TagsGreedy, Tree | |||
POI | Hard | Show TagsFunctional Graph | |||
POI | Hard | Show TagsFunctional Graph |
Warning!
Memory limit for "Spies" is very tight.
Harder
These problems are not Gold level. You may wish to return to these once you're in Platinum.
Status | Source | Problem Name | Difficulty | Tags | |
---|---|---|---|---|---|
COI | Very Hard | Show TagsDP, Tree | |||
Plat | Very Hard | Show TagsBinary Search, DP, Tree | |||
CF | Very Hard | Show TagsDP, Tree | |||
IOI | Insane | Show TagsDP, Tree | |||
CSES | Insane | Show TagsGreedy, Tree | |||
Baltic OI | Insane | Show TagsDP, Tree |
Module Progress:
Join the USACO Forum!
Stuck on a problem, or don't understand a module? Join the USACO Forum and get help from other competitive programmers!