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][i−j]+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∗(i−j)∗w[u][v]+(size[v]−j)∗(size[u]−size[v]−(i−j))∗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
di−1条边;
所以代码中涉及对儿子v值排序,负责都会增加到
O
(
n
∗
l
o
g
n
)
O(n*logn)
O(n∗logn)
大家感觉题目难度怎么样,欢迎留言吐槽~