[bzoj1596] [Usaco2008 Jan]电话网络

  第一眼以为是傻逼题。。结果发现我才是傻逼

  树形dp,因为存在两个相邻的点都没建塔却都被覆盖的情况,比如说自己和父亲都没建塔,但祖父和自己的孩子都建了。。。

  所以一个点应该有三种状态:建塔,没建塔但被某个孩子覆盖(孩子建了塔),自己和所有孩子都没建塔。

  f[i][1],f[i][2],f[i][0]分别表示以上三种状态时,点i所在子树建的最少塔数

  f[i][1]=1+sum{ min( f[j][1],f[j][2],f[j][0] ) },(j是i的儿子);

  f[i][2]=min{ f[j][1]+sum{ min(f[k][1],f[k][2]) } },(j和k都是i的儿子,且k不等于j);sum{ min(f[k][1],f[k][2]) }可以在外面先求出来

  f[i][0]=sum{ f[j][2] };(j是i的儿子)

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 using namespace std;
 5 const int maxn=10233;
 6 struct zs{
 7     short too,pre;
 8 }e[maxn<<1];
 9 short last[maxn],a,b,c,tot;
10 int f[maxn][4];
11 int i,j,k,n,m;
12 short ra;char rx;
13 inline short read(){
14     rx=getchar();ra=0;
15     while(rx<'0'||rx>'9')rx=getchar();
16     while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra;
17 }
18 inline void insert(short a,short b){
19     e[++tot].too=b;e[tot].pre=last[a];last[a]=tot;
20     e[++tot].too=a;e[tot].pre=last[b];last[b]=tot;
21 }
22 void dfs(short x,short pre){
23     f[x][0]=23333;
24     f[x][1]=1;short pos=0,sum=0;
25     for(short i=last[x];i;i=e[i].pre)if(e[i].too!=pre){
26         dfs(e[i].too,x);
27         if(f[e[i].too][2]>f[e[i].too][3])
28             f[x][1]+=f[e[i].too][3];
29         else f[x][1]+=f[e[i].too][2];
30         f[x][2]+=f[e[i].too][0];
31         sum+=f[e[i].too][3];
32         if(!pos||f[e[i].too][1]-f[e[i].too][3]<f[pos][1]-f[pos][3])pos=e[i].too;
33     }
34     if(pos)f[x][0]=sum+f[pos][1]-f[pos][3];
35     f[x][3]=min(f[x][0],f[x][1]);
36 //  printf("%d:  %d %d %d %d\n",x,f[x][0],f[x][1],f[x][2],f[x][3]);
37 }
38 int main(){
39     n=read();
40     for(i=1;i<n;i++)a=read(),b=read(),insert(a,b);
41     dfs(1,0);
42     printf("%d\n",f[1][3]);
43     return 0;
44 }
View Code

//代码中f[i][3]=min(f[i][0],f[i][1]);并没有什么用= =

posted @ 2015-12-21 19:27  czllgzmzl  阅读(253)  评论(0编辑  收藏  举报