树形 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);
}
}

浙公网安备 33010602011771号