码迷,mamicode.com
首页 > 其他好文 > 详细

[bzoj2466][中山市选2009]树_树形dp

时间:2018-07-02 21:30:39      阅读:174      评论:0      收藏:0      [点我收藏+]

标签:题解   main   namespace   最小   按钮   状态   注释   bsp   表示   

树  bzoj-2466 中山市选-2009

题目大意:给定一棵树,每一个点有一个按钮和一个灯泡。如果按下一个点的按钮那么和这个点直接相连的点包括这个点的灯泡的状态会改变。如果是点亮就会变成熄灭,如果是熄灭就会变成点亮。

注释:$1\le n\le 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\n",min(f[1][1],g[1][1]));
	}
}

小结:觉得树形dp很强啊... ...

[bzoj2466][中山市选2009]树_树形dp

标签:题解   main   namespace   最小   按钮   状态   注释   bsp   表示   

原文地址:https://www.cnblogs.com/ShuraK/p/9255596.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!