链接
http://codeforces.com/problemset/problem/1029/E
题解
这题可以等价到另一个经典模型:
给你一棵树,给一些点染色,如果一个点被染色或者其相邻的点被染色,我称其“被控制”,要让所有点都被控制,求最小的染色数。
这个题只是给上述模型加了一个条件:一开始所有根节点的儿子节点都染色了
主要是
d
p
dp
dp状态不太好设计
状态设计的时候,要搞明白这个题里面影响答案的因素是什么,使你难以写出状态转移方程的因素又是什么
我一开始设计状态
f
[
p
o
s
]
[
0
/
1
]
f[pos][0/1]
f[pos][0/1]表示这个点是否被染色的情况下,这棵子树的所有点都满足条件的最少染色数,这样的问题就是,我在计算
f
[
p
o
s
]
[
1
]
f[pos][1]
f[pos][1]的时候,因为这个点被染色了,所以在其子树的问题中,根节点不需要被控制,于是我就尝试加一维表示根节点需不需要被控制
f
[
p
o
s
]
[
0
/
1
]
[
0
/
1
]
f[pos][0/1][0/1]
f[pos][0/1][0/1]表示这个点的根节点染不染色,根节点有没有必要被控制,整棵子树的最少染色点数
那么
f
[
p
o
s
]
[
0
]
[
0
]
=
∑
s
o
n
m
i
n
(
f
[
s
o
n
]
[
0
]
[
1
]
,
f
[
s
o
n
]
[
1
]
[
1
]
)
f[pos][0][0]=\sum_{son} min(f[son][0][1],f[son][1][1])
f[pos][0][0]=∑sonmin(f[son][0][1],f[son][1][1])
f
[
p
o
s
]
[
0
]
[
1
]
=
f
[
v
]
[
1
]
[
1
]
+
∑
s
o
n
̸
=
v
m
i
n
(
f
[
s
o
n
]
[
0
]
[
1
]
,
f
[
s
o
n
]
[
1
]
[
1
]
)
f[pos][0][1]=f[v][1][1]+\sum_{son\not = v} min(f[son][0][1],f[son][1][1])
f[pos][0][1]=f[v][1][1]+∑son̸=vmin(f[son][0][1],f[son][1][1])其中
v
v
v是我枚举的一个儿子结点
f
[
p
o
s
]
[
1
]
[
0
]
=
∑
s
o
n
m
i
n
(
f
[
s
o
n
]
[
0
]
[
0
]
,
f
[
s
o
n
]
[
1
]
[
0
]
)
f[pos][1][0]=\sum_{son}min(f[son][0][0],f[son][1][0])
f[pos][1][0]=∑sonmin(f[son][0][0],f[son][1][0])
f
[
p
o
s
]
[
1
]
[
1
]
=
∑
s
o
n
m
i
n
(
f
[
s
o
n
]
[
0
]
[
0
]
,
f
[
s
o
n
]
[
1
]
[
0
]
)
f[pos][1][1]=\sum_{son}min(f[son][0][0],f[son][1][0])
f[pos][1][1]=∑sonmin(f[son][0][0],f[son][1][0])
在代码中,我把后两维压写了一维,分别用
0
,
1
,
2
,
3
0,1,2,3
0,1,2,3表示
00
,
01
,
10
,
11
00,01,10,11
00,01,10,11
另外,这题可以贪心
代码
#include <bits/stdc++.h>
#define cl(x) memset(x,0,sizeof(x))
#define maxn 400010
#define linf (1ll<<60)
#define iinf 0x3f3f3f3f
#define dinf 1e100
#define eps 1e-8
using namespace std;
typedef long long ll;
ll read(ll x=0)
{
ll c, f=1;
for(c=getchar();!isdigit(c);c=getchar())if(c=='-')f=-f;
for(;isdigit(c);c=getchar())x=x*10+c-48;
return f*x;
}
ll head[maxn], to[maxn], etot, nex[maxn], N, f[maxn][4], ans, g[maxn];
void adde(ll a, ll b){to[++etot]=b;nex[etot]=head[a];head[a]=etot;}
void init()
{
ll a, b, i;
N = read();
for(i=1;i<N;i++)a = read(), b = read(), adde(a,b), adde(b,a);
}
ll min(ll a, ll b, ll c){return min(min(a,b),c);}
ll dfs(ll pos, ll depth, ll pre)
{
ll i, p, s=0;
f[pos][0] = 0;
f[pos][1] = linf;
f[pos][2] = 1;
f[pos][3] = 1;
for(p=head[pos];p;p=nex[p])
if(to[p]!=pre)
{
dfs(to[p],depth+1,pos);
f[pos][0] += min(f[to[p]][1],f[to[p]][3]);
s += min(f[to[p]][1],f[to[p]][3]);
f[pos][2] += min(f[to[p]][0],f[to[p]][2]);
f[pos][3] += min(f[to[p]][0],f[to[p]][2]);
}
for(p=head[pos];p;p=nex[p])
if(to[p]!=pre)
{
f[pos][1] = min(f[pos][1],s-min(f[to[p]][1],f[to[p]][3])+f[to[p]][3]);
}
if(depth==1)ans += f[pos][2]-1;
}
int main()
{
init();
dfs(1,0,0);
cout<<ans;
return 0;
}