树形 DP 入门

WHAT

本身是靠递归定义的,这对于 dp 来说十分滴友好(本身就具有递归结构)

Problem Expressions

Independent Set (Maximum)

TO vertexes

define

对于任意一个图 \(G\) ,确定一个边集 \(V'\) ,使得其中的点两两不相邻

co-NP

Dominating Set (Minimum)

TO vertexes

definition

每个点的覆盖范围一定,在图 \(G\) 中选出一个点集 \(V'\) ,使得 \(G\) 中的每个点都被覆盖

co-NP

Vertex Cover (Minimum)

TO vertexes

definition

每个点可覆盖所有相邻的边,在图 \(G\) 中选出一个点集 \(V'\) ,使得 \(G\) 中的每条边都被覆盖

co-NP

Matching (Maximum)

TO edges

definition

在图 \(G\) 中选出一个点集 \(E'\) ,使得这些边两两不共点

NP-hard

Addition

在特殊条件限制下(例如树、二分图),以上四个问题可以在多项式时间内解决



Problem Solutions

Solution 1st

定义 dp[u][0/1] 表示节点 u 选没选

则很容易得出来以下转移式:

\[dp_{u,1} = w_u + \sum_{v \in \text{son}(u)} dp_{u,0}\\ dp_{u,0} = \sum_{v \in \text{son}(u)} \max(dp_{v,0}, dp_{v,1}) \]

View Code
void DFS(int u, int father) {
	dp[u][0] = 0;
	dp[u][1] = wealth[u];
	for (int v : adj[u]) {
		if (v == father) continue;
		DFS(v, u);
		dp[u][0] += max(dp[v][0], dp[v][1]);
		dp[u][1] += dp[v][0];
	}
}

Solution 2nd

definition

dp[u][0] :被自己覆盖

dp[u][1]:被子节点覆盖

dp[u][2]:被父节点覆盖

State Transformation Function

\[dp_{u,0} = \sum_{v \in \text{son}(u)} \min_{i = 0}^2 dp_{v,i}\\ dp_{u,2} = \sum_{v \in \text{son}(u)} \min_{i = 0}^1 dp_{v,i}\\ dp_{u,1} = \min_{v \in \text{son}(u)} (dp_{u,2}-\min(dp_{v,0},dp_{v,1})+dp_{v,0} \]

View Code
void DFS(int u, int father) {
	dp[u][0] = 1;
	for (int v : adj[u]) {
		if (v == father) continue;
		DFS(v, u);
		dp[u][0] += min({dp[v][0], dp[v][1], dp[v][2]});
		dp[u][2] += min(dp[v][0], dp[v][1]);
	}

	dp[u][1] = INT_MAX / 3;
	for (int v : adj[u]) {
		if (v == father) continue;
		dp[u][1] = min(dp[u][1], dp[u][2] - min(dp[v][0], dp[v][1]) + dp[v][0]);
	}
}
提醒

最后统计答案的时候,由于根节点并没有父亲节点
所以 ans = min(dp[root][0], dp[root][1])

Solution 3rd

稍微转化一下就变得和第一个问题类似

View Code
void DFS(int u, int father) {
	dp[u][0] = 0;
	dp[u][1] = wealth[u];
	for (int v : adj[u]) {
		if (v == father) continue;
		DFS(v, u);
		dp[u][0] += dp[v][1];
		dp[u][1] += min(dp[v][0], dp[v][1]);
	}
}

Solution 4th

我们会惊奇的发现,思路竟然与第二个问题相同

\[dp_{u,0} = \sum_{v \in \text{son}(u)} \max(dp_{v,0}, dp_{v,1})\\ dp_{u,1} = \max_{v \in \text{son}(u)} \{ dp_{u,0} - \max(dp_{v,0}, dp{v,1]} + dp_{v,0} + 1 \} \]

View Code
void DFS(int u, int father) {
	dp[u][0] = 0;
	for (int v : adj[u]) {
		if (v == father) continue;
		DFS(v, u);
		dp[u][0] += max({dp[v][0], dp[v][1]});
	}

	dp[u][1] = INT_MIN / 3;
	for (int v : adj[u]) {
		if (v == father) continue;
		dp[u][1] = max(dp[u][1], dp[u][0] - max(dp[v][0], dp[v][1]) + dp[v][0] + 1);
	}
}
posted @ 2026-02-02 19:08  Yangyihao  阅读(2)  评论(0)    收藏  举报