洛谷 P2585 [ ZJOI 2006 ] 三色二叉树 —— 树形DP
题目:https://www.luogu.org/problemnew/show/P2585
首先,三色其实记录两种状态:是绿色,不是绿色 即可,因为红蓝可以随意取反;
一开始因为懒得还原出树,所以写了个错误贪心-_-
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int const maxn=500005; int k,mx,mn,siz[maxn]; char a[maxn]; int dfs() { k++; siz[k]=1; int tmp=k;// int nw=a[k]-'0'; if(nw==0)return siz[k]; else if(nw==1)siz[tmp]+=dfs(); else siz[tmp]+=dfs(),siz[tmp]+=dfs(); return siz[tmp]; } void dfsmx(int col) { if(col)mx++; k++; int nw=a[k]-'0'; if(nw==0)return; else if(nw==1)dfsmx(!col); else { if(siz[k+1]<siz[k]-siz[k+1])dfsmx(!col),dfsmx(0); else dfsmx(0),dfsmx(!col); } } void dfsmn(int col) { if(col)mn++; k++; int nw=a[k]-'0'; if(nw==0)return; else if(nw==1)dfsmn(0); else { if(siz[k+1]>siz[k]-siz[k+1])dfsmn(!col),dfsmn(0); else dfsmn(0),dfsmn(!col); } } int main() { scanf("%s",a+1); k=0; dfs(); k=0; dfsmx(1); k=0; dfsmn(0); printf("%d %d\n",mx,mn); return 0; }
实际上是树形DP啦,f[x][0/1] 表示 x 选非绿色或绿色的最大答案,g[x][0/1] 表示最小答案;
然后转移即可。
代码如下:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int const maxn=5e5+5; int n,k,ls[maxn],rs[maxn],f[maxn][2],g[maxn][2]; char a[maxn]; void init() { k++; int nw=a[k]-'0'; int tmp=k; if(nw==0)return; else if(nw==1)ls[tmp]=k+1,init(); else ls[tmp]=k+1,init(),rs[tmp]=k+1,init(); } void dfs(int x) { f[x][1]=1; g[x][1]=1; if(!ls[x])return; else if(!rs[x]) { int u=ls[x]; dfs(u); f[x][0]+=f[u][1]; f[x][1]+=f[u][0]; g[x][0]+=g[u][0]; g[x][1]+=g[u][0]; } else { int u=ls[x],v=rs[x]; dfs(u); dfs(v); f[x][0]+=max(f[u][0]+f[v][1],f[u][1]+f[v][0]); f[x][1]+=f[u][0]+f[v][0]; g[x][0]+=min(g[u][0]+g[v][1],g[u][1]+g[v][0]); g[x][1]+=g[u][0]+g[v][0]; } } int main() { scanf("%s",a+1); k=0; init(); dfs(1); printf("%d %d\n",max(f[1][0],f[1][1]),min(g[1][0],g[1][1])); return 0; }