树形动态规划

错题

P8867 [NOIP2022] 建造军营

易分析出tarjan+树形DP

正如题解所说,有两种取消后效性的方法:加维或换定义

加维好想,但是比较难写,不过我倾向于加维,思路清晰不易错

p.s. 一定一定,要保证方程无后效性

md,拿了个有后效性的方程搞了2个小时

P4099 [HEOI2013]SAO

超级好的一道题,对于我这种DP蒟蒻来说

首先,这道题不能脱离树而去做DAG(自己研究了也会发现)

易想到DP方程\(f[x][j]\)为点\(x\)在子树\(x\)内排在第\(j\)为的方案数

难点在于转移:由于定义为子树内,考虑对儿子\(v\)的排序往\(x\)上合并

注意考虑有向边的限制,列出DP方程为:

\[f[x][j]=\begin{cases}\sum^j_{k=1}f[x][k]*C^{k-1}_{j-1}*C^{siz[x]-k}_{siz[x]+siz[v]-j}*\sum^{siz[v]}_{l=j-k+1}f[v][l] \hspace{0.5cm},x\to v \\ \sum^j_{k=1}f[x][k]*C^{k-1}_{j-1}*C^{siz[x]-k}_{siz[x]+siz[v]-j}*\sum^{j-k}_{l=1}f[v][l] \hspace{1.1cm},v\to x \end{cases} \]

比较考验推导能力,建议试试,时间复杂度为\(O(n^3)\)

然后就是观察到\(f[v][l]\)可以前缀和预处理,优化掉了一个\(O(n)\),总时间复杂度为\(O(n^2)\)

时间复杂度分析

重头戏来了

乍一看这个式子,每个点搜过一遍,对于每个点\(v\)的穷举次数为\(siz[x]*(siz[x]+siz[v])\),乍一看感觉像\(O(n^3)\),再想想又不到,感觉有个常数级别的差距或可能为\(O(n^2logn)\),结果是\(O(n^2)\)

仔细思考这个过程:每次枚举\(siz[x]*(siz[x]+siz[v])\),对于\(siz[x]*siz[v]\)来说,相当于枚举整棵树的所有点对,故为\(O(n^2)\)……

树的直径

方法1:两次DFS

方法2:树形DP

我们不改变树的形态(即根不变),发现此时直径上总会有一个点深度最小,即它和它的全部子树包含直径的全部点集,因此我们做出以每个点为根的最长链,一定有一个点包含正确答案。

设f[i]表示以i为根的最长链长度

设g[i]表示以i为根的次长链长度,且该次长链不与最长链有交集

DFS枚举子树后转移即可

p.s.转移时注意跟次长链比较

p.s.s.这种记录次优值的思路在单源次短路中也有体现

树的重心

换根

最大权独立集

基环树DP

剖环成树,然后做树形DP即可

找环

拓扑排序

易知一遍拓扑后只剩下环,记录即可

注意基环树存储时用的是无向图,因此进队条件改为in[v]==1

边界处理

正常来说,走环的时候要往一个方向,因此只要让它不回头就不会重复走,于是很容易想到pre记录上一个走到的点

然而这是错误的!

考虑二元环,我下一个走的点就是我上一个走到的点,所以到不了另一个(这\(\beta\)二元环整了我一下午+一晚上)

于是考虑记录上一步走的边

但是这是无向图呀,我连了双边,记不到回去的边啊

考虑网络流算法时建反图,让tot从2开始计数,就是为了可以用i^1来快速跳转到自己的反边

于是我们利用这个技巧,问题解决

p.s.断点本身就是异类,基环树DP大致思路都是断边成树,然后整棵树做DP,像这道题我的做法就会引发一系列细节问题,但正常思路就不会(说不定某一题用我的方法更好呢)

P6830 [IOI2020] 连接擎天树

首先发现存在\(p[i][j]=3\)是非法的,因此图为基环树森林

先把树连出来,再拼环即可

换根DP

两次DFS

posted @ 2024-10-31 17:24  Zhone_lb  阅读(11)  评论(0)    收藏  举报