【树形dp】P2585 [ZJOI2006]三色二叉树
一棵二叉树可以按照如下规则表示成一个由0、1、2组成的字符序列,我们称之为“二叉树序列S”:
例如,下图所表示的二叉树可以用二叉树序列S=21200110来表示。
你的任务是要对一棵二叉树的节点进行染色。每个节点可以被染成红色、绿色或蓝色。并且,一个节点与其子节点的颜色必须不同,如果该节点有两个子节点,那么这两个子节点的颜色也必须不相同。给定一棵二叉树的二叉树序列,请求出这棵树中最多和最少有多少个点能够被染成绿色。
输入输出格式
输入数据由多组数据组成。
每组数据仅有一行,不超过10000个字符,表示一个二叉树序列。
对于每组输入数据,输出仅一行包含两个整数,依次表示最多和最少有多少个点能够被染成绿色。
样例输入
1122002010
样例输出
5 2
用dp[x][0/1/2]和f[x][0/1/2]分别记录x节点为绿/红/蓝的最多/最少的绿色节点数
这样就可以树形dp了
代码
#include<bits/stdc++.h> using namespace std; const int maxn=5e5+5; char c[maxn]; int dp[maxn][3],f[maxn][3],cnt,ans=1; void dfs(int x) { if(c[x]=='0') { f[x][0]=dp[x][0]=1; return; } dfs(++cnt); if(c[x]=='1') { dp[x][0]=max(dp[x+1][1],dp[x+1][2])+1; dp[x][1]=max(dp[x+1][0],dp[x+1][2]); dp[x][2]=max(dp[x+1][0],dp[x+1][1]); f[x][0]=min(f[x+1][1],f[x+1][2])+1; f[x][1]=min(f[x+1][0],f[x+1][2]); f[x][2]=min(f[x+1][0],f[x+1][1]); } else { int r=++cnt; dfs(r); dp[x][0]=max(dp[x+1][1]+dp[r][2],dp[x+1][2]+dp[r][1])+1; dp[x][1]=max(dp[x+1][0]+dp[r][2],dp[x+1][2]+dp[r][0]); dp[x][2]=max(dp[x+1][0]+dp[r][1],dp[x+1][1]+dp[r][0]); f[x][0]=min(f[x+1][1]+f[r][2],f[x+1][2]+f[r][1])+1; f[x][1]=min(f[x+1][0]+f[r][2],f[x+1][2]+f[r][0]); f[x][2]=min(f[x+1][0]+f[r][1],f[x+1][1]+f[r][0]); } ans=max(ans,dp[x][0]); } int main() { freopen("a.in","r",stdin); freopen("a.out","w",stdout); scanf("%s",c+1); dfs(++cnt); printf("%d ",ans); printf("%d",min(f[1][0],min(f[1][2],f[1][1]))); return 0; }