zoukankan      html  css  js  c++  java
  • 解题报告: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
    ",min(dp[0][0],min(dp[0][1],dp[0][2])));
    	return 0;
    }
    
  • 相关阅读:
    图片剪切
    js事件(Event)知识整理
    原生JavaScript事件详解
    underscore源码解析
    win7 vi工具
    开源java数据库库
    win7快捷键
    win7 绿色版MySQL安装与配置
    maven jetty
    javax inect
  • 原文地址:https://www.cnblogs.com/tlx-blog/p/12843511.html
Copyright © 2011-2022 走看看