BZOJ-1864-[Zjoi2006]三色二叉树(树形dp)
Description
Input
仅有一行,不超过500000个字符,表示一个二叉树序列。
Output
输出文件也只有一行,包含两个数,依次表示最多和最少有多少个点能够被染成绿色。
Sample Input
1122002010
Sample Output
5 2
HINT
Source
题解
这道题我们考虑dp
我们先把树给构造出来(可以用栈,也可以用dfs)
建完树后,我们用f[i][0/1/2][0]表示i节点填绿/蓝/红色的最小答案,f[i][0/1/2][1]表示i节点填绿/蓝/红色的最大答案
我们考虑i节点从两个儿子转移
f[i][0][0]=min(f[s1][1][0]+f[s2][2][0],f[s1][2][0]+f[s2][1][0])
f[i][1][0]=min(f[s1][0][0]+f[s2][2][0],f[s1][2][0]+f[s2][0][0])
f[i][2][0]=min(f[s1][0][0]+f[s2][1][0],f[s1][1][0]+f[s2][0][0])
f[i][0/1/2][1]转移同理
1 #include<bits/stdc++.h> 2 #define N 500005 3 using namespace std; 4 int tot,top; 5 int Stack[N]; 6 int f[N][3][2]; 7 char s[N]; 8 int main(){ 9 scanf("%s",s+1); 10 int len=strlen(s+1); 11 for (int i=len;i>=1;i--) 12 if (s[i]=='2'){ 13 int x=Stack[top],y=Stack[--top]; 14 tot++; 15 f[tot][0][0]=min(f[x][1][0]+f[y][2][0],f[x][2][0]+f[y][1][0])+1; 16 f[tot][1][0]=min(f[x][2][0]+f[y][0][0],f[x][0][0]+f[y][2][0]); 17 f[tot][2][0]=min(f[x][1][0]+f[y][0][0],f[x][0][0]+f[y][1][0]); 18 f[tot][0][1]=max(f[x][1][1]+f[y][2][1],f[x][2][1]+f[y][1][1])+1; 19 f[tot][1][1]=max(f[x][2][1]+f[y][0][1],f[x][0][1]+f[y][2][1]); 20 f[tot][2][1]=max(f[x][1][1]+f[y][0][1],f[x][0][1]+f[y][1][1]); 21 Stack[top]=tot; 22 } else 23 if (s[i]=='1'){ 24 int x=Stack[top]; 25 tot++; 26 f[tot][0][0]=min(f[x][1][0],f[x][2][0])+1; 27 f[tot][1][0]=min(f[x][0][0],f[x][2][0]); 28 f[tot][2][0]=min(f[x][0][0],f[x][1][0]); 29 f[tot][0][1]=max(f[x][1][1],f[x][2][1])+1; 30 f[tot][1][1]=max(f[x][0][1],f[x][2][1]); 31 f[tot][2][1]=max(f[x][0][1],f[x][1][1]); 32 Stack[top]=tot; 33 } else{ 34 tot++; 35 f[tot][0][0]=f[tot][0][1]=1; 36 Stack[++top]=tot; 37 } 38 int Max=max(f[tot][0][1],max(f[tot][1][1],f[tot][2][1])); 39 int Min=min(f[tot][0][0],min(f[tot][1][0],f[tot][2][0])); 40 printf("%d %d",Max,Min); 41 return 0; 42 }