[Zjoi2006]三色二叉树(bzoj1864)(洛谷2585)题解

原题地址:https://www.luogu.org/problemnew/show/P2585html

题目大意:能够把一个节点染成三种颜色,父节点和两个子节点(能够有一个)颜色不能相同。求最多(少)能有多少个点能被染成绿色数组


因为是一棵树,多决策的问题,很明显的树形DP。ui

关于树形DP详见https://www.cnblogs.com/lizitong/p/10020914.htmlspa

二维状态,dp[i][j] j取0,1,2表示三种颜色。表示以这个编号为父节点取这个颜色时候有dp[i][j]个点能被染成绿色。code

DFS搜到最底,而后给叶节点附上初值。htm

而后回溯更新。blog

以最小值为例。string

dpmi[x][1] = min(dpmi[x][1],min(dpmi[l[x]][2]+dpmi[r[x]][3],dpmi[l[x]][3]+dpmi[r[x]][2])+1);
dpmi[x][2] = min(dpmi[x][2],min(dpmi[l[x]][1]+dpmi[r[x]][3],dpmi[l[x]][3]+dpmi[r[x]][1]));
dpmi[x][3] = min(dpmi[x][3],min(dpmi[l[x]][1]+dpmi[r[x]][2],dpmi[l[x]][2]+dpmi[r[x]][1]));it

若是这个点是绿色,就比较子节点分别为其余两种颜色的大小,而后+1io

若是这个点是其余颜色,就比较这两个点子节点分别是另外两种颜色和的大小。

最后输出父节点的最大(小)状态。

分别用l和r数组存左右儿子。

细节较多,上代码。

#include<cstdio> #include<algorithm> #include<string> #include<cstring>
#define N 500005
using namespace std; char c[N]; struct edge { int to; int nxt; int from; }eg[N]; int head[N]; int cnt = 1; int ct = 1; int dpma[N][4]; int dpmi[N][4]; int l[N]; int r[N]; void add(int x,int y) { eg[cnt].to = y; eg[cnt].nxt = head[x]; eg[cnt].from = x; head[x] = cnt++; } void buildtree(int x) { if(c[x]=='2') { add(x,++ct); l[x] = ct; buildtree(ct); add(x,++ct); r[x] = ct; buildtree(ct); }else if(c[x]=='1') { add(x,++ct); l[x] = ct; buildtree(ct); }else { return ; } } void dfsma(int x) { if(l[x]==0&&r[x]==0) { dpma[x][1] = 1; return ; }else { if(l[x]) { dfsma(l[x]); dpma[x][1] = max(dpma[x][1],max(dpma[l[x]][2]+dpma[r[x]][3],dpma[l[x]][3]+dpma[r[x]][2])+1); dpma[x][2] = max(dpma[x][2],max(dpma[l[x]][1]+dpma[r[x]][3],dpma[l[x]][3]+dpma[r[x]][1])); dpma[x][3] = max(dpma[x][3],max(dpma[l[x]][1]+dpma[r[x]][2],dpma[l[x]][2]+dpma[r[x]][1])); } if(r[x]) { dfsma(r[x]); dpma[x][1] = max(dpma[x][1],max(dpma[l[x]][2]+dpma[r[x]][3],dpma[l[x]][3]+dpma[r[x]][2])+1); dpma[x][2] = max(dpma[x][2],max(dpma[l[x]][1]+dpma[r[x]][3],dpma[l[x]][3]+dpma[r[x]][1])); dpma[x][3] = max(dpma[x][3],max(dpma[l[x]][1]+dpma[r[x]][2],dpma[l[x]][2]+dpma[r[x]][1])); } } } void dfsmi(int x) { if(l[x]==0&&r[x]==0) { dpmi[x][1] = 1; dpmi[x][2] = 0; dpmi[x][3] = 0; return ; }else { if(l[x]) { dfsmi(l[x]); dpmi[x][1] = min(dpmi[x][1],min(dpmi[l[x]][2]+dpmi[r[x]][3],dpmi[l[x]][3]+dpmi[r[x]][2])+1); dpmi[x][2] = min(dpmi[x][2],min(dpmi[l[x]][1]+dpmi[r[x]][3],dpmi[l[x]][3]+dpmi[r[x]][1])); dpmi[x][3] = min(dpmi[x][3],min(dpmi[l[x]][1]+dpmi[r[x]][2],dpmi[l[x]][2]+dpmi[r[x]][1])); } if(r[x]) { dfsmi(r[x]); dpmi[x][1] = min(dpmi[x][1],min(dpmi[l[x]][2]+dpmi[r[x]][3],dpmi[l[x]][3]+dpmi[r[x]][2])+1); dpmi[x][2] = min(dpmi[x][2],min(dpmi[l[x]][1]+dpmi[r[x]][3],dpmi[l[x]][3]+dpmi[r[x]][1])); dpmi[x][3] = min(dpmi[x][3],min(dpmi[l[x]][1]+dpmi[r[x]][2],dpmi[l[x]][2]+dpmi[r[x]][1])); } } } int main() { scanf("%s",c+1); buildtree(1); memset(dpmi,0x3f,sizeof(dpmi)); dpmi[0][1] = 0; dpmi[0][2] = 0; dpmi[0][3] = 0; dfsma(1); dfsmi(1); printf("%d ",max(max(dpma[1][1],dpma[1][2]),dpma[1][3])); printf("%d",min(min(dpmi[1][1],dpmi[1][2]),dpmi[1][3])); }
相关文章
相关标签/搜索