树型DP
Posted Virtualtan
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了树型DP相关的知识,希望对你有一定的参考价值。
声明
参考课件和讲授来自Accelerator
找树的直径
树的直径定义为一个树中最长的一条链。
- 一种做法比较显然,我们可以大力 DP,维护出一个节点向下的最长链F(x)和次长链G(x),保证F,G不出自同一个儿子,然后用二者加和来更新答案,同时更新父亲节点的最长链和次长链。
- 另外一种做法,则可以这样:随便选择一个点,然后找到距离这个点最远的点 A, 再以 A 为源点,找到距离 A 最远的一个点 B, AB 路径上的点就是直径。
对于第一种做法比较适合拓展到其他形式的 DP 上去,更新时维护次小的想法也比较适合推荐。同时可以求出任意一个子树的直径。
第二种方法我们可以拿出一些有利于解题的性质。
第二种方法不支持负权,这需要注意下。
找树的重心
对于一棵 n 个节点的无根树,找到一个点 A,使得把树变成以该点为根的有根树时,最大子树的结点数最小。A 叫做重心。
求法很简单,求 size 即可。
容易发现重心的各个儿子的 size<= \(n/2\)
支配集与独立集
1.求一个最大点集使得其中点的个数尽可能多且该集合中不存在两个点有边相连。
2.求一个最小点集使得树上的每个点都存在一个集合中的点与其相连。
两个问题很有代表性,这里讲一下解法。
第一个问题比较好解决,考虑令 f(x) 表示 x 点在集合中,以x 为根的子树能选取的最多点数,g(x) 表示x 点不在集合中,以 x 为根的子树能选取的最多点数。
考虑按照题意的合法性转移即可。
f(x) = ∑g(son)
g(x) =∑ max f(son), g(son)
第二个问题相对复杂,我们称选择的点能够“覆盖”与其相连的点,那么考虑一个点的合法状态有 3 种,分别设选则该点的状态为 f(x),这个点被儿子覆盖为 g(x), 这个点被父亲覆盖为h(x) 。f, h 函数的转移都很简单,对于 g, 分类讨论即可。
DP 的两种处理方法
前面默认我们都是使用了 DFS 来递归处理子树,然后回溯更新节点,但是实际操作中会存在问题。
Windows 下默认栈空间大小为 4Mb, Linux 下为 8Mb, 大量递归会堆栈溢出。
考虑这个转移的过程只需要所有的儿子都被更新完
。我们BFS 这颗树,然后按照bfs序倒过来处理 DP 是可以得到同样的效果的。
至此我们解决了这个问题。
树形 DP 为什么相较其他 DP 来比有难度
- 在树上进行,相较于序列,更新的方式更多,对思维难度和代码实现难度要求都更高。
- 对 DP 优化的考察更为明显,如何通过更优秀的状态表示将一个复杂度更高的动态规划降维。
- 背包问题的拓展以及树上背包。
接下来我们将通过习题来解决这些问题。
题
以上是关于树型DP的主要内容,如果未能解决你的问题,请参考以下文章