树型动态规划
一、基本概念
树型动态规划,顾名思义,就是在“树”的数据结构上做动态规划,通过有限次地遍历树,记录相关信息,以求解问题。通常,动态规划都是线性的或者建立在图上的,分为逆推和顺推。
①叶->根,即根的子节点传递有用的消息给根,之后由根得出最优解的过程。这种方式DP的题目应用比较多。
②根->叶,即需要取所有点作为一次根节点进行求值,此时父节点得到了整棵树的信息,只需要去除这个儿子的DP值的影响,然后再转移给这个儿子,这样就能达到根->叶的顺序
动态规划的顺序:一般按照后序遍历的顺序,几处理完儿子再处理当前结点,才符合树的子结构的性质。
实现方式:树型DP是通过记忆化搜索实现的,因此采用的是递归方式,
时间复杂度:树型动态规划的时间复杂度基本上是O(n);若有附加维m,则是O(n * m)
二、经典问题
1.树的重心
对于一颗n个节点的无根树,找到一个点,使得把树变成以该点为根的有根树时,最大子树的节点最小,换句话说,删除这个点后最大连通块的节点数最小,那么这个点就是树的重心。
解法:任选一个节点作为根进行dfs然后根据定义动态规划寻找树的重心。
2.树的最长路径(最远点对)
给定一颗n个结点的边带权树找到一条最长的路径,换句话说,要找到两个点,使得他们的距离最远,他们之间的路径就是树的最长路径
解法:用d1[i],d2[i]记录以i为根的子树中到叶节点的最大值和次大值,j是i的儿子
①d1[j] + dis[i][j] > d1[i] 则d2[i] = d1[i],d1[i] = d1[j] + dis[i][j]
②d1[j] + dis[i][j] > d2[i] 则d2[i] = d1[j] + dis[i][j]
3.树的中心问题
给出一颗带权的树,求树中的点,使得此点到树中的其他节点的最远距离最近
分析:从任意一个点i出发的最长路径的可能形态有两种。
①从i点出发向上,即终点不在以i为根的子树中的最长路径长度为u[i]
②从i点出发向下,即终点在以i为根的子树中的最长路径长度为d1[i]
注意:第一种里面不要重复经过i点
分别用c1[i]和c2[i]记录d1[i]和d2[i]是从哪个子树更新来的。
(1)
①d1[j] + dis[i][j] > d1[i] 则d2[i] = d1[i],d1[i] = d1[j] + dis[i][j]
②d1[j] + dis[i][j] > d2[i] 则d2[i] = d1[j] + dis[i][j]
(2)设prt[i]=x (i的父节点)
如果c1[x] != i,u[i] = max(d1[x],u[x]) + dist[x][i]
否则u[i] = max(d2[x],u[x])+ dist[x][i]
(3)
在最后n个节点中找到最大值
t[i] = max(u[i],d1[i])
(4)
树的中心 ans= min(t[i])
4.普通的树形DP
给定一颗树,现在要从中选出最少的节点,使得所有边至少有一个端点在选中的集合中。
分析:
点的取舍可以看成一个决策,f[j][1]和f[j][0]决定
当这个点不取的时候他的所有儿子都得取 f[i][0] = sum(f[j][1])
当这个点不取的时候他儿子取不取都行这个时候需要选择一个最优策略,f[i][1] = sum(min(f[j][1],f[j][0]) + 1;
普通的树形DP中,常常会采用叶 - > 根的转移形式,根据父节点的状态确定子节点的状态,若子节点有多个则需要一一枚举,将子节点(子树)的DP值合并。
树形DP还有一个重要拓展是与各类树形数据结构集合,例如Trie上的DP,AC自动机的DP,后缀自动机的DP等。
有时我们的图可以不简单限制于树,在树的基础上进行简单的扩展,也可以得到一些能用DP解决的例子,例如环 + 外向树(在有根树的基础上,添加了一条某节点指向根的边的图)上的DP,仙人掌(每条边至多存在于一个简单环)上的DP等。