……

解题报告:luogu P2585

题目链接:P2585 [ZJOI2006]三色二叉树
_shy 大佬求助,就尝试切了切。
树形计数 \(dp\) ,比树上背包简单多了。
\(dp_{i,0/1/2}\)\(i\) 号点颜色为绿,红,蓝时绿色的个数,然后处理出每个节点的儿子数(我可能做麻烦了),分类讨论即可,方程太多,就看代码吧。
注意初始化。
其实可以直接在序列上算,然而我不熟,就先转化成图再做的。

\(Code\):

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
using namespace std;

#define MAXN 500005
#define inf 2147483647

char c[MAXN];
int t;
struct node
{
	int to,nxt;
}e[MAXN<<1];
int head[MAXN],cnt=0;
int deg[MAXN];
int dp[MAXN][3];
int son1[MAXN],son2[MAXN];

void add(int u,int v)
{
	e[++cnt].to=v;
	e[cnt].nxt=head[u];
	head[u]=cnt;
	return;
}

void join(int u,int v){add(u,v),add(v,u);}

int dfs1(int cur)
{
	if(c[cur]=='1'){join(cur,cur+1);return dfs1(cur+1);}
	if(c[cur]=='0') return cur;
	else 
	{
		join(cur,cur+1);
		int now=dfs1(cur+1)+1;
		join(cur,now);
		return dfs1(now);
	}
}

void dfs2(int cur,int fa)
{
	for(int i=head[cur];i;i=e[i].nxt)
	{
		int j=e[i].to;
		if(j==fa) continue;
		else dfs2(j,cur),deg[cur]++;
	}
	return;
}

void dfs(int cur,int fa)
{
	son1[cur]=0,son2[cur]=0;
	if(!deg[cur]){dp[cur][0]=1,dp[cur][1]=dp[cur][2]=0;return;}
	for(int i=head[cur];i;i=e[i].nxt)
	{
		int j=e[i].to;
		if(j==fa) continue;
		if(!son1[cur]) son1[cur]=j;
		else son2[cur]=j;
		dfs(j,cur);
	}
	if(deg[cur]==1) 
	{
		dp[cur][0]=max(dp[son1[cur]][1],dp[son1[cur]][2])+1;
		dp[cur][1]=max(dp[son1[cur]][0],dp[son1[cur]][2]);
		dp[cur][2]=max(dp[son1[cur]][0],dp[son1[cur]][1]);
	}
	else if(deg[cur]==2)
	{
		dp[cur][0]=max(dp[son1[cur]][1]+dp[son2[cur]][2],dp[son1[cur]][2]+dp[son2[cur]][1])+1;
		dp[cur][1]=max(dp[son1[cur]][0]+dp[son2[cur]][2],dp[son1[cur]][2]+dp[son2[cur]][0]);
		dp[cur][2]=max(dp[son1[cur]][0]+dp[son2[cur]][1],dp[son1[cur]][1]+dp[son2[cur]][0]);
	}
	return;
}

void dfss(int cur,int fa)
{
	if(!deg[cur]){dp[cur][0]=1,dp[cur][1]=dp[cur][2]=0;return;}
	for(int i=head[cur];i;i=e[i].nxt)
	{
		int j=e[i].to;
		if(j==fa) continue;
		dfss(j,cur);
	}
	if(deg[cur]==1) 
	{
		dp[cur][0]=min(dp[son1[cur]][1],dp[son1[cur]][2])+1;
		dp[cur][1]=min(dp[son1[cur]][0],dp[son1[cur]][2]);
		dp[cur][2]=min(dp[son1[cur]][0],dp[son1[cur]][1]);
	}
	else if(deg[cur]==2)
	{
		dp[cur][0]=min(dp[son1[cur]][1]+dp[son2[cur]][2],dp[son1[cur]][2]+dp[son2[cur]][1])+1;
		dp[cur][1]=min(dp[son1[cur]][0]+dp[son2[cur]][2],dp[son1[cur]][2]+dp[son2[cur]][0]);
		dp[cur][2]=min(dp[son1[cur]][0]+dp[son2[cur]][1],dp[son1[cur]][1]+dp[son2[cur]][0]);
	}
	return;
}

int main()
{
	scanf("%s",c);
	int len=strlen(c);
	memset(dp,0,sizeof(dp));
	dfs1(0);
	dfs2(0,0);
	dfs(0,0);
	printf("%d ",max(dp[0][0],max(dp[0][1],dp[0][2])));
	for(int i=0;i<len;i++) dp[i][0]=dp[i][1]=dp[i][2]=inf;
	dfss(0,0);
	printf("%d\n",min(dp[0][0],min(dp[0][1],dp[0][2])));
	return 0;
}
posted @ 2020-05-07 15:48  童话镇里的星河  阅读(119)  评论(0编辑  收藏  举报