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