树形DP小结

24 篇文章 0 订阅

本文用于记录一些做过的树形dp题

一些做题技巧

  1. 对于断边问题,我们有两种处理思路:一种是把边的贡献放在儿子上,令一种是先断掉所有边然后把边的贡献放在父亲上
  2. 多叉树转二叉树——左儿子右兄弟表示法
void Pre(int x){//多叉树转二叉树
    vis[x]=true;
    for(int i=1;i<=n;i++)
        if(!vis[i]&&graph[x][i]){
            r[i]=l[x];
            l[x]=i;
            Pre(i);
        }
    return;
}

多叉树转二叉树后的最小可能深度

  1. 开动态栈记录祖先
    [IOI2005]Riv 河流

  2. 长链剖分优化有一维状态为深度维的DP

  3. 虚树

模型小结

树的最大独立集

f [ u ] [ 1 / 0 ] f[u][1/0] f[u][1/0]表示点 u u u选/不选,以 u u u为根的子树中的最大独立集

f [ u ] [ 0 ] = ∑ m a x { f [ v ] [ 0 ] , f [ v ] [ 1 ] } f[u][0]=\sum max\{f[v][0],f[v][1]\} f[u][0]=max{f[v][0],f[v][1]}
f [ u ] [ 1 ] = 1 + ∑ f [ v ] [ 0 ] f[u][1]=1+\sum f[v][0] f[u][1]=1+f[v][0]

树的最小点覆盖集

f [ u ] [ 1 / 0 ] f[u][1/0] f[u][1/0]表示点 u u u选/不选,以 u u u为根的子树中的最小点覆盖集

f [ u ] [ 0 ] = ∑ f [ v ] [ 1 ] f[u][0]=\sum f[v][1] f[u][0]=f[v][1]
f [ u ] [ 1 ] = 1 + ∑ m i n { f [ v ] [ 0 ] , f [ v ] [ 1 ] } f[u][1]=1+\sum min\{f[v][0],f[v][1]\} f[u][1]=1+min{f[v][0],f[v][1]}

树的重心

树形背包

void dfs(int u,int fa){//树形背包基本模板
	siz[u]=1;
	for(int i=head[u];i;i=edge[i].nxt){
		int v=edge[i].v;
		if(v==fa) continue;
		dfs(v,u);
		for(int j=0;j<=min(m,siz[u]);j++){
			for(int k=0;k<=min(m-j,siz[v]);k++){
				//f[u][j+k] <-- w(f[u][j],f[v][k])
			}
		}
		siz[u]+=siz[v];
	} 
}

时间复杂度
= ∑ i ∑ j , k ∈ s o n i s i z j × s i z k =\sum_i\sum_{j,k\in son_i}siz_j\times siz_k =ij,ksonisizj×sizk
= ∑ i ∑ j , k ∈ s o n i ( ∑ x [ x ∈ s u b t r e e j ] ) × ( ∑ y [ y ∈ s u b t r e e j ] ) =\sum_i\sum_{j,k\in son_i}(\sum_x[x\in subtree_j])\times(\sum_y[y\in subtree_j]) =ij,ksoni(x[xsubtreej])×(y[ysubtreej])
因为 L C A ( x , y ) = i LCA(x,y)=i LCA(x,y)=i,即任何两点只在 l c a lca lca处有贡献
所以时间复杂度是 O ( n 2 ) O(n^2) O(n2)

[CTSC1997]选课
LuoguP1273 有线电视网
[JSOI2008]魔兽地图

换根dp

经典例题:给定一棵树,对于每个点,求该点到与它距离最远的点的距离。
f [ x ] [ 0 ] f[x][0] f[x][0]表示 x x x的子树中 的点到 x x x最远距离,用 f [ x ] [ 1 ] f[x][1] f[x][1]表示 x x x的子树中 的点到 x x x次远距离,用 f [ x ] [ 2 ] f[x][2] f[x][2]表示 不在 x x x的子树中 的点到 x x x最远距离
第一次dp求出 f [ x ] [ 0 ] , f [ x ] [ 1 ] f[x][0],f[x][1] f[x][0],f[x][1],第二次dp用父亲的 f [ f a ] [ 0 ] , f [ f a ] [ 1 ] f[fa][0],f[fa][1] f[fa][0],f[fa][1]求出儿子的 f [ x ] [ 2 ] f[x][2] f[x][2]
最后答案即为 m a x ( f [ x ] [ 0 ] , f [ x ] [ 2 ] ) max(f[x][0],f[x][2]) max(f[x][0],f[x][2])

基环树

树上动态dp

树上最优选点/选边问题

[POI2011] DYN-Dynamite
CF671D 【Roads in Yusland】

  • 树上选不相交链问题
    该问题满足最优子结构,即如果要在 u u u的子树里面选链,我们可以先对 u u u的每一个儿子 v v v的子树求出最优解,再在 u u u子树的剩余未选择部分里面选链。
    P5021 [NOIP2018 提高组] 赛道修建
    XSY4197 Snow

与树有关的区间dp

f [ i ] [ j ] f[i][j] f[i][j]表示节点i到节点j构成树的贡献,按照区间长度从小到大的顺序进行区间dp。
[NOIP2003 提高组] 加分二叉树
f [ i ] [ j ] f[i][j] f[i][j]表示节点i到节点j构成树的最大加分。
二叉树的加分取决于谁是根,于是我们在区间内枚举根 k k k来转移:
f [ i ] [ i ] = a [ i ] f[i][i]=a[i] f[i][i]=a[i]
f [ i ] [ j ] = m a x { f [ i ] [ k − 1 ] × f [ k + 1 ] [ j ] + f [ k ] [ k ] } ( i ≠ j ) f[i][j]=max\{f[i][k-1]\times f[k+1][j]+f[k][k]\}(i\not=j) f[i][j]=max{f[i][k1]×f[k+1][j]+f[k][k]}(i=j)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值