每日一题 P2585 [ZJOI2006]三色二叉树 树形dp

这篇博客详细解析了P2585[ZJOI2006]三色二叉树问题的树形DP解决方案。作者首先介绍了题目背景和思路,指出可以通过枚举节点及其子节点颜色进行状态转移。然后,提供了建立图的代码,并采用DFS遍历处理。接着,博主展示了如何处理不同节点情况下的最大值和最小值更新。最后,给出了完整的C++代码实现,输出最大值和最小值。该文适合对树形DP有一定了解的读者深入学习。
摘要由CSDN通过智能技术生成

每日一题 P2585 [ZJOI2006]三色二叉树 树形dp


思路挺简单的一道蓝色题目,枚举当前点的颜色与儿子颜色做转移
其实可以直接在字符串上dfs,但是怕麻烦出错还是把他先按照常规建成了我熟悉的图 代码如下

#include <bits/stdc++.h>
#define int long long
#define endl "\n"
#define MAXN 1000005
using namespace std;
struct EDGE
{
    int to,next;
} edge[MAXN];
int head[MAXN],ptr;
void add_edge(int u,int v)
{
    edge[++ptr].to=v;
    edge[ptr].next=head[u];
    head[u]=ptr;
}
void add(int a,int b)
{
    add_edge(a,b);
    add_edge(b,a);
}
int Rmax[MAXN],Gmax[MAXN],Bmax[MAXN];
int Rmin[MAXN],Gmin[MAXN],Bmin[MAXN];

string s;
int ptrn;
void dfs1()
{
    int now=++ptrn;
    if(s[now]=='0')
    {
        Rmax[now]=Rmin[now]=Bmax[now]=Bmin[now]=0;
        Gmax[now]=Gmin[now]=1;
        return;
    }
    if(s[now]=='2')
    {
        add(now,ptrn+1);
        dfs1();
    }
    add(now,ptrn+1);
    dfs1();
}
void dfs2(int now,int fa)
{
    int cnt=0,son[2];
    for(int p=head[now]; p; p=edge[p].next)
    {
        int to=edge[p].to;
        if(to==fa)continue;
        son[cnt++]=to;
        dfs2(to,now);
    }
    if(cnt==1)
    {
        Rmax[now]=max(Gmax[son[0]],Bmax[son[0]]);
        Gmax[now]=max(Rmax[son[0]],Bmax[son[0]])+1;
        Bmax[now]=max(Gmax[son[0]],Rmax[son[0]]);
        Rmin[now]=min(Gmin[son[0]],Bmin[son[0]]);
        Gmin[now]=min(Rmin[son[0]],Bmin[son[0]])+1;
        Bmin[now]=min(Gmin[son[0]],Rmin[son[0]]);
    }
    else if(cnt==2)
    {
        for(int i=0; i<=1; i++)
        {
            Rmax[now]=max(Gmax[son[!i]]+Bmax[son[i]],Rmax[now]);
            Gmax[now]=max(Rmax[son[!i]]+Bmax[son[i]],Gmax[now]);
            Bmax[now]=max(Gmax[son[!i]]+Rmax[son[i]],Bmax[now]);
            Rmin[now]=min(Gmin[son[!i]]+Bmin[son[i]],Rmin[now]);
            Gmin[now]=min(Rmin[son[!i]]+Bmin[son[i]],Gmin[now]);
            Bmin[now]=min(Gmin[son[!i]]+Rmin[son[i]],Bmin[now]);
        }
        Gmax[now]++,Gmin[now]++;
    }
}
signed main()
{
    memset(Rmin,0x3f,sizeof(Rmin));
    memset(Gmin,0x3f,sizeof(Gmin));
    memset(Bmin,0x3f,sizeof(Bmin));
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    cin>>s;
    s=' '+s;
    dfs1();
    dfs2(1,1);
    cout<<max(max(Rmax[1],Gmax[1]),Bmax[1])<<' '<<min(min(Rmin[1],Gmin[1]),Bmin[1]);
}



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值