题解P2458 [SDOI2006]保安站岗
很显然的树形dp。
设f[i][0/1/2]表示:
f[i][0]:被父亲管着 由于它有父亲管着所以它的儿子只能自己管自己或者被它的儿子管
f[i][1]:自己管自己 随便儿子什么状态都行
f[i][2]:被儿子管着 这时候我们要分类讨论 如果儿子都是被儿子管的我们必须弄出一个儿子管它 否则有一个儿子不被儿子的儿子管就行
最后答案 由于1没有父亲 所以是Min(f[1][1],f[1][2])
由于我一开始想错了,没考虑儿子管父亲,WA了两次,写个题解记一下,以后少犯这种错。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<stdio.h> 2 #define it register int 3 #define il inline 4 #define Min(a,b) (a<b?a:b) 5 const int N=1000005; 6 typedef long long ll; 7 int h[N],nxt[N],adj[N],a[N],u,v,t,fa[N],n; 8 ll f[N][3]; 9 il void add(){ 10 nxt[++t]=h[u],h[u]=t,adj[t]=v,nxt[++t]=h[v],h[v]=t,adj[t]=u; 11 } 12 il void dfs(it x){ 13 f[x][1]=a[x]; 14 it fl=0,fx=0; 15 for(it i=h[x],j;i;i=nxt[i]) 16 if((j=adj[i])!=fa[x]) 17 fa[j]=x,dfs(j),f[x][0]+=Min(f[j][1],f[j][2]),f[x][1]+=Min(Min(f[j][0],f[j][1]),f[j][2]),f[x][2]+=Min(f[j][1],f[j][2]),fl|=(f[j][2]>f[j][1]); 18 if(!fl){ 19 ll now=0x7ffffff; 20 for(it i=h[x],j;i;i=nxt[i]) if((j=adj[i])!=fa[x]) now=Min(now,f[j][1]-f[j][2]); 21 f[x][2]+=now; 22 } 23 } 24 il void fr(int &num){ 25 num=0;char c=getchar();int p=1; 26 while(c<'0'||c>'9') c=='-'?p=-1,c=getchar():c=getchar(); 27 while(c>='0'&&c<='9') num=num*10+c-'0',c=getchar(); 28 num*=p; 29 } 30 int main(){ 31 fr(n); 32 for(it i=1,x;i<=n;++i){ 33 fr(u),fr(a[u]),fr(x); 34 while(x--) fr(v),add(); 35 } 36 dfs(1),printf("%lld",Min(f[1][1],f[1][2])); 37 return 0; 38 }