JZOJ7月22日提高组T1 三色树
题目
Description
给出一个N个节点的无根树,每条边有非负边权,每个节点有三种颜色:黑,白,灰。
一个合法的无根树满足:树中不含有黑色结点或者含有至多一个白色节点。
现在希望你通过割掉几条树边,使得形成的若干树合法,并最小化割去树边权值的和。
Input
第一行一个正整数N,表示树的节点个数。
第二行N个整数Ai,表示i号节点的颜色,0 表示黑色,1表示白色,2表示灰色。
接下来N-1行每行三个整数Xi Yi Zi,表示一条连接Xi和Yi权为Zi的边。
Output
输出一个整数表示其最小代价。
Sample Input
5
0 1 1 1 0
1 2 5
1 3 3
5 2 5
2 4 16
Sample Output
10
样例解释:
花费10的代价删去边(1, 2)和边(2, 5)。
Data Constraint
20%的数据满足N≤10。
另外30%的数据满足N≤100,000,且保证树是一条链。
100%的数据满足N≤300,000,0≤Zi≤1,000,000,000,Ai∈{0,1,2}。
题解
题意
n
n
n个节点,颜色为0\1\2
对于一个合法树,要求没有颜色0或最多一个颜色1
求出满足最大合法森林需要删去边的最小代价
分析
由于每个节点只有三种颜色,状态简单,很容易想到用树形DP来做这道题。
上面这句话是CJZ巨佬所述 (但我这种蒟蒻就想不到树形DP)
设
f
[
i
]
[
0
]
f[i][0]
f[i][0]表示以节点
i
i
i为根的子树中不含黑色节点的最小代价
设
f
[
i
]
[
1
]
f[i][1]
f[i][1]表示以节点
i
i
i为根的子树中不含白色节点的最小代价
设
f
[
i
]
[
2
]
f[i][2]
f[i][2]表示以节点
i
i
i为根的子树中只含一个白色节点的最小代价
先行告知:
s
o
n
son
son表示
i
i
i的儿子,
v
v
v表示
i
i
i和
s
o
n
son
son连接的那条边的权值,
a
[
i
]
a[i]
a[i]表示节点
i
i
i的颜色,
i
n
f
inf
inf正无穷
f
[
i
]
[
0
]
f[i][0]
f[i][0]转移:
f
[
i
]
[
0
]
=
{
(
a
[
i
]
=
0
)
i
n
f
(
a
[
i
]
≠
0
)
∑
s
o
n
m
i
n
{
f
[
s
o
n
]
[
0
]
v
+
m
i
n
{
f
[
s
o
n
]
[
1
]
f
[
s
o
n
]
[
2
]
f[i][0]=\begin{cases}(a[i]=0)inf\\(a[i]≠0)∑_{son}min\begin{cases}f[son][0]\\v+min\begin{cases}f[son][1]\\f[son][2]\end{cases}\end{cases} \end{cases}
f[i][0]=⎩⎪⎪⎪⎨⎪⎪⎪⎧(a[i]=0)inf(a[i]=0)∑sonmin⎩⎪⎨⎪⎧f[son][0]v+min{f[son][1]f[son][2]
解释:
当节点
i
i
i的颜色是黑色时
以节点
i
i
i为根的子树中不含黑色节点是不存在的
所以
f
[
i
]
[
0
]
f[i][0]
f[i][0]设为
i
n
f
inf
inf
当节点
i
i
i的颜色是白色时
对于每个儿子节点
可以全部白色,或者割掉当前节点和儿子节点之间的边,那么儿子节点选什么都无所谓,求个
m
i
n
min
min值就可以了
f
[
i
]
[
1
]
f[i][1]
f[i][1]转移(其实跟
f
[
i
]
[
0
]
f[i][0]
f[i][0]转移基本一样)
f
[
i
]
[
1
]
=
{
(
a
[
i
]
=
1
)
i
n
f
(
a
[
i
]
≠
1
)
∑
s
o
n
m
i
n
{
f
[
s
o
n
]
[
1
]
v
+
m
i
n
{
f
[
s
o
n
]
[
0
]
f
[
s
o
n
]
[
2
]
f[i][1]=\begin{cases}(a[i]=1)inf\\(a[i]≠1)∑_{son}min\begin{cases}f[son][1]\\v+min\begin{cases}f[son][0]\\f[son][2]\end{cases}\end{cases} \end{cases}
f[i][1]=⎩⎪⎪⎪⎨⎪⎪⎪⎧(a[i]=1)inf(a[i]=1)∑sonmin⎩⎪⎨⎪⎧f[son][1]v+min{f[son][0]f[son][2]
至于解释嘛,对照
f
[
i
]
[
0
]
f[i][0]
f[i][0]的自己思考
f
[
i
]
[
2
]
f[i][2]
f[i][2]转移
f
[
i
]
[
2
]
=
{
(
a
[
i
]
=
1
)
∑
s
o
n
m
i
n
{
f
[
s
o
n
]
[
1
]
v
+
m
i
n
{
f
[
s
o
n
]
[
0
]
f
[
s
o
n
]
[
2
]
(
a
[
i
]
≠
1
)
f
[
i
]
[
1
]
−
m
a
x
(
m
i
n
{
f
[
s
o
n
]
[
1
]
v
+
m
i
n
{
f
[
s
o
n
]
[
0
]
f
[
s
o
n
]
[
2
]
−
f
[
s
o
n
]
[
2
]
)
f[i][2]=\begin{cases}(a[i]=1)∑_{son}min\begin{cases}f[son][1]\\v+min\begin{cases}f[son][0]\\f[son][2]\end{cases}\end{cases}\\(a[i]≠1)f[i][1]-max(min\begin{cases}f[son][1]\\v+min\begin{cases}f[son][0]\\f[son][2]\end{cases}\end{cases}-f[son][2]) \end{cases}
f[i][2]=⎩⎪⎪⎪⎪⎪⎪⎪⎪⎨⎪⎪⎪⎪⎪⎪⎪⎪⎧(a[i]=1)∑sonmin⎩⎪⎨⎪⎧f[son][1]v+min{f[son][0]f[son][2](a[i]=1)f[i][1]−max(min⎩⎪⎨⎪⎧f[son][1]v+min{f[son][0]f[son][2]−f[son][2])
不要看错
解释:
当当前节点的颜色是白色时
那么它的儿子不能选白色
跟
f
[
i
]
[
1
]
f[i][1]
f[i][1]一样
当当前节点不是白色
那么就可以让某个儿子节点的要求放宽一点
求出放宽要求后减少哪些代价
再用没有白色节点的
f
[
i
]
[
1
]
f[i][1]
f[i][1]减去最大减少代价
结合代码理解