树形dp的几种问题
树的最大独立集
题目描述
对于一棵\(n\)个结点的无根树,选出尽可能多的结点,使得任意两个结点均不相邻(称为最大独立集),然后输入\(n-1\)条无向边,输出一个最大独立集。
解决方法
-
对于无根树,只要任选一个根,无根树就变成了有根树
-
结点\(i\)有两种状态:选和不选。如果不选\(i\),问题就转化为求出\(i\)的所有儿子的\(dp\)值再相加;如果选\(i\),问题就转化成\(i\)的所有孙子的\(dp\)值之和
-
状态转移方程为:
\[dp(i) = max
\left\{
\begin{aligned}
1 + \sum_{j \in gs(i)} dp(j),\sum_{j \in s(i)} dp(j)
\end{aligned}
\right\}
\]
代码编写
void dfs(int u)
{
vis[u] = 1 ;
for(auto v:son[u])
{
if(vis[v] == 1) continue ;
dfs(v) ;
dp[u][1] += dp[v][0] ;
dp[u][0] += max(dp[v][0], dp[v][1]) ;
}
return ;
}
树的重心
题目描述
对于一棵n个结点的无根树,找到一个点,使得把树变成以该点为根的有根树时,最大子树的结点数最小。
解决思路
-
先以任意结点为根,将无根树转为有根树。
-
\(dp_i\)表示以i为根的子树的结点个数。所以
\[dp[i]=\sum_{j \in s(i)} dp[j] + 1
\]
- 删除结点\(i\)后,最大连通块有\(dp[j]_{max}\)个结点
实现
void dfs(int u)
{
vis[u] = 1 ;
for(auto v:son[u])
{
if(vis[v] == 1) continue ;
dfs(v) ;
dp[u] = dp[v] + 1 ;
}
}
树的最远点对
题目描述
对于一棵\(n\)个结点的无根树,找到一条最长路径。(找到两个点,使得它们距离最远)
解决思路
-
先把无根树转为有根树。
-
对于任意结点\(i\),经过\(i\)的最长路就是连接\(i\)的两棵不同子树\(u\)和\(v\)的最深叶子的路径
实现
略

浙公网安备 33010602011771号