题解P2458 [SDOI2006]保安站岗

题目: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了两次,写个题解记一下,以后少犯这种错。

 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 }
View Code
原文地址:https://www.cnblogs.com/Kylin-xy/p/11730643.html