【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]])。
注意空节点的处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | #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; } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步