【bzoj1864】[ZJOI2006]三色二叉树 树形dp
题目描述
输入
仅有一行,不超过500000个字符,表示一个二叉树序列。
输出
输出文件也只有一行,包含两个数,依次表示最多和最少有多少个点能够被染成绿色。
样例输入
1122002010
样例输出
5 2
题解
比较简单的一道树形dp
f[i]表示i为绿色时以i为根的子树中绿色节点的个数和,g[i]表示i不为绿色时以i为根的子树中绿色节点的个数和。
由于这是一棵二叉树,很容易推出状态转移方程为f[i]=g[l[i]]+g[r[i]];g[i]=min/max(f[l[i]]+g[r[i]],g[l[i]]+f[r[i]])。
注意空节点的处理
#include <stdio.h> #include <string.h> int f[300001] , g[300001] , l[300001] , r[300001] , p , n; char str[500002]; int min(int a , int b) { return a < b ? a : b; } int max(int a , int b) { return a > b ? a : b; } void init() { p ++ ; n ++ ; int now = n; if(str[p] == '2') { l[now] = n + 1; init(); r[now] = n + 1; init(); } else if(str[p] == '1') { l[now] = n + 1; init(); } } void dpmax(int x) { if(!x) return; dpmax(l[x]); dpmax(r[x]); f[x] = g[l[x]] + g[r[x]] + 1; g[x] = max(f[l[x]] + g[r[x]] , g[l[x]] + f[r[x]]); } void dpmin(int x) { if(!x) return; dpmin(l[x]); dpmin(r[x]); f[x] = g[l[x]] + g[r[x]] + 1; g[x] = min(f[l[x]] + g[r[x]] , g[l[x]] + f[r[x]]); } int main() { scanf("%s" , str + 1); init(); dpmax(1); printf("%d " , max(f[1] , g[1])); memset(f , 0 , sizeof(f)); memset(g , 0 , sizeof(g)); dpmin(1); printf("%d\n" , min(f[1] , g[1])); return 0; }