[bzoj2466][中山市选2009]树_树形dp
Posted shurak
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[bzoj2466][中山市选2009]树_树形dp相关的知识,希望对你有一定的参考价值。
树 bzoj-2466 中山市选-2009
题目大意:给定一棵树,每一个点有一个按钮和一个灯泡。如果按下一个点的按钮那么和这个点直接相连的点包括这个点的灯泡的状态会改变。如果是点亮就会变成熄灭,如果是熄灭就会变成点亮。
注释:$1le nle n$
想法:啥jb数据范围啊,不是树形dp吗?看着挺像高斯消元。看网上题解全是枚举自由元???O(n)就可以为什么要$O(n^3)$???
我们来看看树形dp...
状态:f[pos][bool]表示按下这个点的按钮之后,这个点亮(或不亮),它的所有子孙都亮的最小代价。g[pos][bool]表示不按这个点的按钮,这个点亮(不亮),它的所有子孙都亮的方案数。
转移:
f[pos][1]=min(f[pos][0] + f[to[i]][0] , f[pos][1] + g[to[i]][0]).
f[pos][0]=min(f[pos][0] + g[to[i]][0] , f[pos][1] + f[to[i]][0]).
g[pos][1]=min(g[pos][0] + f[to[i]][1] , g[pos][1] + g[to[i]][1]).
g[pos][0]=min(g[pos][0] + g[to[i]][1] , g[pos][1] + f[to[i]][1]).
最后,附上丑陋的代码... ...
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #define N 110 using namespace std; int to[N<<1],nxt[N<<1],head[N],tot; int f[N][5],g[N][5],n; inline void add(int x,int y) { to[++tot]=y; nxt[tot]=head[x]; head[x]=tot; } void dfs(int pos,int fa) { f[pos][1]=1,f[pos][0]=n<<1; g[pos][0]=0,g[pos][1]=n<<1; for(int i=head[pos];i;i=nxt[i]) { if(to[i]==fa) continue; dfs(to[i],pos); int f1=f[pos][1],f0=f[pos][0],g1=g[pos][1],g0=g[pos][0]; f[pos][1]=min(f0+f[to[i]][0],f1+g[to[i]][0]); f[pos][0]=min(f0+g[to[i]][0],f1+f[to[i]][0]); g[pos][1]=min(g0+f[to[i]][1],g1+g[to[i]][1]); g[pos][0]=min(g0+g[to[i]][1],g1+f[to[i]][1]); } } void original() { tot=0; memset(head,0,sizeof head); } int main() { while(~scanf("%d",&n)) { if(!n) return 0; original(); for(int x,y,i=1;i<=n-1;i++) scanf("%d%d",&x,&y),add(x,y),add(y,x); dfs(1,0); printf("%d ",min(f[1][1],g[1][1])); } }
小结:觉得树形dp很强啊... ...
以上是关于[bzoj2466][中山市选2009]树_树形dp的主要内容,如果未能解决你的问题,请参考以下文章