树(tree)
【问题描述】
图论中的树为一个无环的无向图。给定一棵树,每个节点有一盏指示灯和一个按钮。如果节点的按扭被按了,那么该节点的灯会从熄灭变为点亮(当按之前是熄灭的),或者从点亮到熄灭(当按之前是点亮的)。并且该节点的直接邻居也发生同样的变化。 开始的时候,所有的指示灯都是熄灭的。请编程计算最少要按多少次按钮,才能让所有节点的指示灯变为点亮状态。
【输入格式】
输入文件有多组数据。
输入第一行包含一个整数n,表示树的节点数目。每个节点的编号从1到n。
输入接下来的n – 1行,每一行包含两个整数x,y,表示节点x和y之间有一条无向边。
当输入n为0时,表示输入结束。
【输出格式】
对于每组数据,输出最少要按多少次按钮,才能让所有节点的指示灯变为点亮状态。每一组数据独占一行。
输入样例:
3
1 2
1 3
0
输出样例:
1
这道题目莫名让我想到了以前见过有一个死胖子用手指按字母然后附近的都会点到,不过我忘记题目了~~
言归正传,题目已经很明确告诉你是一棵树,那么就可以很容易想到是树形DP,寻找状态转移方程是本题的关键。
首先,我们用f[x][0]
表示以x为根节点的子树下,x开着灯,而他的儿子,孙子,孙子的儿子…也都开灯的最少次数;
而f[x][1]
表示以x为根节点的子树下,x关灯,而他的子辈都开着灯的最少次数;
f[x][2]
则表示以x为根节点的子树下,x关灯,他的子辈也都关灯的最少次数;
那么f[x][3]
表示什么呢,就是以x为根节点的子树下,x开灯,他的子辈也都关灯的最少次数,很显然,这是不存在的,所以f[x][3]
排除啦。
把F数组的定义弄清楚了,那么接下来的就好办了!
也是分三步:
1. f[x][0]
最好算,因为如果我和我的子辈都开着灯了,那么我的亲朋好友就不用开灯了啦,所以f[x][0]+=f[x][2]
2.接着就算f[x][2]
和f[x][1]
怎么算呢?因为我们还要考虑到有可能在我的子辈按按钮按了个奇数,那么最后的状态就要改变呀(ps:真是个无聊的儿子。。),所以我需要一个变量来算我途中按了多少次(这个变量我称为按钮计数)。然后就是如何“科学的推卸责任了”,我们也要用一个变量,来表示最少次数,那就是tmp+=min(f[x][2],f[x][1])
啦!
3.f[x][2]和f[x][1]