树形dp考试题目题解2024-3-9

s i z e [ u ] size[u] size[u]表示 u u u为根的子树的节点数量

T1:感染树(CodeForces - 1689C)

题目大意: n个顶点的二叉树,根1被感染,每次操作为删除一个顶点和其连边,感染蔓延1条边,问最多能够保留多少结点不被感染也不被删除。

标签: 树形dp、贪心

题解: dp[u]以u为根的子树u为第一个被感染的点,最多能够保留多少结点不被感染也不被删除。

因为是二叉树,优先选择 s i z e [ v ] size[v] size[v]大的儿子删除 v v v保留 s i z e [ v ] − 1 size[v]-1 size[v]1个节点,另一个儿子一定被沾染,处理相同子问题即可。

d p [ u ] = m a x ( s i z e [ v 1 ] − 1 + d p [ v 2 ] , s i z e [ v 2 ] − 1 + d p [ v 1 ] ) ; dp[u]=max(size[v1]-1+dp[v2],size[v2]-1+dp[v1]); dp[u]=max(size[v1]1+dp[v2],size[v2]1+dp[v1]);

单独考虑没有儿子和只有一个儿子的情况。

T2:有根树(CodeForces - 1153D)

题目大意: n个点的树,每个点的权值0或1代表取子树所有节点的最小值或最大值,k个叶子节点配分1~k,问怎么样分配使得根的值最大。

标签:树形dp

题解: dp[u]以u为根的子树 给其叶子节点分配 1~size[u]的最大值,也可以理解为:若dp[u]=x,u为根的最大值为叶子的值中的第x小,不管给叶子分配的值是不是1-size[u],是不是连续,x表示第x小。

如果 a [ u ] = 1 a[u]=1 a[u]=1,表示取最大值: d p [ u ] = m a x ( d p [ u ] , s i z e [ u ] − s i z e [ v ] + d p [ v ] ) ; dp[u]=max(dp[u],size[u]-size[v]+dp[v]); dp[u]=max(dp[u],size[u]size[v]+dp[v]);
含义为反正要取最大值,就取儿子中 s i z e [ v ] − d p [ v ] size[v]-dp[v] size[v]dp[v]最小的,这样就把 [ s i z e [ u ] − s i z e [ v ] + 1 , s i z e [ u ] ] [size[u]-size[v]+1,size[u]] [size[u]size[v]+1,size[u]]区间分配给 v v v,这样最大值就是 s i z e [ u ] − s i z e [ v ] + d p [ v ] ) ) size[u]-size[v]+dp[v])) size[u]size[v]+dp[v]))

如果 a [ u ] = 0 a[u]=0 a[u]=0,表示取最小值: d p [ u ] = s i z e [ u ] − ∑ ( s i z e [ v ] − d p [ v ] + 1 ) + 1 ; dp[u]=size[u]-\sum(size[v]-dp[v]+1) +1; dp[u]=size[u](size[v]dp[v]+1)+1;
每个儿子的区间为 [ 1 , s i z e [ v ] ] [1,size[v]] [1,size[v]],其中 [ d p [ v ] , s i z e [ v ] ] [dp[v],size[v]] [dp[v],size[v]]区间都是比较大的值,都会被浪费,所以 d p [ u ] dp[u] dp[u]取儿子中的最小值 就会有 ∑ ( s i z e [ v ] − d p [ v ] + 1 ) \sum(size[v]-dp[v]+1) (size[v]dp[v]+1) 个数被浪费。
希望你能理解,仔细想想为什么要求和,所有子树中的叶子的值都不相同哦。

第二种方法:dp[u]表示u为根的子树种,根能获得第x大(和第一种方法相反(互补))
如果 a [ u ] = 1 a[u]=1 a[u]=1,表示取最大值: d p [ u ] = m i n ( d p [ u ] , d p [ v ] ) ; dp[u]=min(dp[u],dp[v]); dp[u]=min(dp[u],dp[v]);
如果 a [ u ] = 0 a[u]=0 a[u]=0,表示取最小值: d p [ u ] = s u m ( d p [ v ] ) dp[u]=sum(dp[v]) dp[u]=sum(dp[v])

T3:染色树(洛谷 - P3177)

题目大意:n个点的树,都有边权,从中选若干个点(可以是0个)染成黑色,其余为白色,求任意黑和黑,白和白点之间距离和的最大值,怎么染色呢?

标签:背包、树形dp

题解 d p [ u ] [ i ] dp[u][i] dp[u][i] u u u 为根的子树,其中选 i i i 个点染成黑色的最大收益。
d p [ u ] [ i ] = m a x ( d p [ u ] [ i ] , d p [ u ] [ i − j ] + d p [ v ] [ j ] + v a l ) ; dp[u][i]=max(dp[u][i],dp[u][i-j]+dp[v][j]+val); dp[u][i]=max(dp[u][i],dp[u][ij]+dp[v][j]+val)
其中val表示u->v这条边对答案的贡献

val=v子树中黑点数量*u子树中其它黑点数量*w[u][v]+v子树中白点数量*u子树中其它白点数量*w[u][v]

v a l = j ∗ ( i − j ) ∗ w [ u ] [ v ] + ( s i z e [ v ] − j ) ∗ ( s i z e [ u ] − s i z e [ v ] − ( i − j ) ) ∗ w [ u ] [ v ] ; val=j*(i-j)*w[u][v]+(size[v]-j)*(size[u]-size[v]-(i-j))*w[u][v]; val=j(ij)w[u][v]+(size[v]j)(size[u]size[v](ij))w[u][v];

T4:选边树(AtCoder - abc259_f )

题目大意: n个的树,有边权(有负数),选若干边使得边权和最大,要求每个点的已选边后的度不能超过 d i d_i di;
标签: 树形dp、贪心
题解: dp[u][1] u为根的子树中的最佳答案,u选与父亲的边。dp[u][0] u为根的子树中的最佳答案,u不选与父亲的边。

d p [ u ] [ 0 ] + = d p [ v ] [ 0 ; dp[u][0]+=dp[v][0; dp[u][0]+=dp[v][0
如果 d p [ v ] [ 0 ] < d p [ v ] [ 1 ] + w [ u ] [ v ] dp[v][0]<dp[v][1]+w[u][v] dp[v][0]<dp[v][1]+w[u][v]可以贪心的让u选u->v这条边。
所以优先选择差值 d p [ v ] [ 1 ] + w [ u ] [ v ] − d p [ v ] [ 0 ] dp[v][1]+w[u][v] -dp[v][0] dp[v][1]+w[u][v]dp[v][0]最大的 d i d_i di条边;
当然且保证所有值>0,不都没必要选;
等价于把 d p [ v ] [ 0 ] dp[v][0] dp[v][0]换成 d p [ v ] [ 1 ] + w [ u ] [ v ] dp[v][1]+w[u][v] dp[v][1]+w[u][v]
同理:
d p [ u ] [ 1 ] + = d p [ v ] [ 0 ] ; dp[u][1]+=dp[v][0]; dp[u][1]+=dp[v][0]
如果 d p [ v ] [ 0 ] < d p [ v ] [ 1 ] + w [ u ] [ v ] dp[v][0]<dp[v][1]+w[u][v] dp[v][0]<dp[v][1]+w[u][v]可以贪心的让u选u->v这条边。
所以优先选择差值 d p [ v ] [ 1 ] + w [ u ] [ v ] − d p [ v ] [ 0 ] dp[v][1]+w[u][v] -dp[v][0] dp[v][1]+w[u][v]dp[v][0]最大的 d i − 1 d_i-1 di1条边;
所以代码中涉及对儿子v值排序,负责都会增加到 O ( n ∗ l o g n ) O(n*logn) O(nlogn)

大家感觉题目难度怎么样,欢迎留言吐槽~

  • 11
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值