目录:
分析:
这道题目,每个点我们都可以分为两个状态:放或是不放,然后再进行分类讨论就好了:(f为不放的,g为放的最小数)
1)
s1=∑min{g[e[i].to],f[e[i].to]}
s
1
=
∑
m
i
n
{
g
[
e
[
i
]
.
t
o
]
,
f
[
e
[
i
]
.
t
o
]
}
.即当我们父节点放时,子节点可放可不放
2)
s2=∑g[e[i].to]
s
2
=
∑
g
[
e
[
i
]
.
t
o
]
.即当我们父节点不放时,为保证每个路都监测到,我们的子节点必须要放
在上文,我们用了s1,s2进行统计,是为了保证节点修改后的值不影响当前节点的结果
最后一点,在处理环时,可以不再dp重点,但仍取该点的结果
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define LL long long
using namespace std;
inline LL read() {
LL d=0,f=1;char s=getchar();
while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
while(s>='0'&&s<='9'){d=d*10+s-'0';s=getchar();}
return d*f;
}
struct edg{
int to,next;
}e[200001];
int c=0;
int ls[100001];
int tf[100001],g[100001],f[100001];
void add(int a,int b)
{
e[c]=(edg){b,ls[a]};
ls[a]=c++;
}
void dp(int x,int y)
{
int s1=1,s2=0;
for(int i=ls[x];~i;i=e[i].next)
{
if(!tf[e[i].to])
{
tf[e[i].to]=1;
if(e[i].to==y) continue;
dp(e[i].to,x);
s1+=min(g[e[i].to],f[e[i].to]);
}
s2+=g[e[i].to];
}
g[x]=s1;
f[x]=s2;
}
int main()
{
memset(ls,-1,sizeof ls);
int n=read(),a;
for(int i=1;i<=n;i++)
{
a=read();
for(int j=1;j<=a;j++)
add(i,read());
}
tf[1]=1;
dp(1,0);
printf("%d",min(f[1],g[1]));
return 0;
}