1. 程式人生 > >ZJOI2016 三色二叉樹

ZJOI2016 三色二叉樹

首先 此題給出的時一個可以代表二叉樹的一個序列

直接遞迴把樹建出來就好了。

然後考慮DP。

比較容易想到的是一個f[i][3]的DP,分別代表以i為根時,i染三種顏色的最大數目。

直接根據限制轉移即可,但程式碼比較長。

考慮(程式碼)簡單一點的,

實際上,由於我們只在意綠色的染了多少,所以染其他兩種色沒有區別(也就是可以完全互相轉換)。

所以考慮是否可以設f[i][2],分別代表以i為根時,i染或不染綠色的最大數目。

同樣直接根據限制轉移。

#include <bits/stdc++.h>
#define LL long long
using namespace
std; const int MAXN=5e5+10; char Tr[MAXN]; int Id,Cnt,tot,head[MAXN],Son[MAXN][3],Min[MAXN][2],Max[MAXN][2]; void Build (int Nx) { Son[Nx][0]=Tr[++Cnt]-'0'; if (!Son[Nx][0]) return; for (int i=1;i<=Son[Nx][0];++i) { Son[Nx][i]=++Id; Build (Id); } } void Tr_DP (int Nx) {
for (int i=1;i<=Son[Nx][0];++i) Tr_DP (Son[Nx][i]); if (Son[Nx][0]==0) { Min[Nx][1]=Max[Nx][1]=1; return; } else if (Son[Nx][0]==1) { int Nex=Son[Nx][1]; Min[Nx][1]+=Min[Nex][0]+1; Max[Nx][1]+=Max[Nex][0]+1; Min[Nx][0]=min (Min[Nex][0
], Min[Nex][1]); Max[Nx][0]=max (Max[Nex][0], Max[Nex][1]); } else { int Nex1=Son[Nx][1], Nex2=Son[Nx][2]; Min[Nx][1]+=Min[Nex1][0]+Min[Nex2][0]+1; Max[Nx][1]+=Max[Nex1][0]+Max[Nex2][0]+1; Min[Nx][0]=min (Min[Nex1][0]+Min[Nex2][1], Min[Nex1][1]+Min[Nex2][0]); Max[Nx][0]=max (Max[Nex1][0]+Max[Nex2][1], Max[Nex1][1]+Max[Nex2][0]); } } int main () { scanf ("%s", Tr+1); Build (++Id); Tr_DP (1); printf ("%d %d\n", max (Max[1][0], Max[1][1]), min (Min[1][0], Min[1][1]) ); return 0; }