洛谷 P2585 [ ZJOI 2006 ] 三色二叉树 —— 树形DP

题目:https://www.luogu.org/problemnew/show/P2585

首先,三色其实记录两种状态:是绿色,不是绿色 即可,因为红蓝可以随意取反;

一开始因为懒得还原出树,所以写了个错误贪心-_-

#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;
}

 

posted @ 2018-09-19 21:58  Zinn  阅读(138)  评论(0编辑  收藏  举报