洛谷 P2585 [ZJOI2006]三色二叉树(树形dp)
传送门
解题思路
用dp[i][0]表示第i个节点染绿色的以i为根的子树的最大(最小)染绿色总数,dp[i][1]表示染红色,dp[i][2]表示染蓝色。
各种情况转移即可。
写完代码后发现,dp[i][1]和dp[i][2]相等,所以其实可以合并起来,这样能少许多代码量。
AC代码
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<cmath> 5 #include<algorithm> 6 using namespace std; 7 const int maxn=500005; 8 int n,dp1[maxn][3],dp2[maxn][3]; 9 int v[maxn][3],cnt=1; 10 char c; 11 void dfs(int id,int num){ 12 if(num==0) return; 13 for(int i=1;i<=num;i++){ 14 cnt++; 15 scanf("%c",&c); 16 v[id][i]=cnt; 17 v[cnt][0]=c-'0'; 18 dfs(cnt,v[cnt][0]); 19 } 20 } 21 void dfs2(int u){ 22 if(v[u][0]==0){ 23 dp1[u][0]=dp2[u][0]=1; 24 dp1[u][1]=dp1[u][2]=dp2[u][1]=dp2[u][2]=0; 25 return; 26 } 27 if(v[u][0]==1){ 28 int son=v[u][1]; 29 dfs2(son); 30 dp1[u][0]=max(dp1[son][1],dp1[son][2])+1; 31 dp1[u][1]=max(dp1[son][0],dp1[son][2]); 32 dp1[u][2]=max(dp1[son][0],dp1[son][1]); 33 dp2[u][0]=min(dp2[son][1],dp2[son][1])+1; 34 dp2[u][1]=min(dp2[son][0],dp2[son][2]); 35 dp2[u][2]=min(dp2[son][0],dp2[son][1]); 36 return; 37 } 38 if(v[u][0]==2){ 39 int son1=v[u][1],son2=v[u][2]; 40 dfs2(son1); 41 dfs2(son2); 42 dp1[u][0]=max(dp1[son1][1]+dp1[son2][2],dp1[son1][2]+dp1[son2][1])+1; 43 dp1[u][1]=max(dp1[son1][0]+dp1[son2][2],dp1[son1][2]+dp1[son2][0]); 44 dp1[u][2]=max(dp1[son1][0]+dp1[son2][1],dp1[son1][1]+dp1[son2][0]); 45 dp2[u][0]=min(dp2[son1][1]+dp2[son2][2],dp2[son1][2]+dp2[son2][1])+1; 46 dp2[u][1]=min(dp2[son1][0]+dp2[son2][2],dp2[son1][2]+dp2[son2][0]); 47 dp2[u][2]=min(dp2[son1][0]+dp2[son2][1],dp2[son1][1]+dp2[son2][0]); 48 } 49 } 50 int main(){ 51 cin>>c; 52 v[1][0]=c-'0'; 53 dfs(1,v[1][0]); 54 dfs2(1); 55 cout<<max(max(dp1[1][0],dp1[1][1]),dp1[1][2])<<" "<<min(min(dp2[1][0],dp2[1][1]),dp2[1][2]); 56 return 0; 57 }