原题地址: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])); }