[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 }
//代码中f[i][3]=min(f[i][0],f[i][1]);并没有什么用= =