Description
Input
仅有一行,不超过500000个字符,表示一个二叉树序列。
Output
输出文件也只有一行,包含两个数,依次表示最多和最少有多少个点能够被染成绿色。
Sample Input
1122002010
Sample Output
5 2
分析:
第一次写dp1A,✿✿ヽ(°▽°)ノ✿
如果一个节点被染成绿色,那么ta的父亲,儿子和最近兄弟都不能是绿色
也就是说,一个绿色节点最多影响4个节点,最少影响1个
设计状态
f[i][0/1/2]
当前i节点,状态是0/1/2,最多有多少个绿色节点
g[i][0/1/2]
当前i节点,状态是0/1/2,最少有多少个绿色节点
tip
转移的时候耐下心来慢慢写就好
(瞎扯,ctrl+c和ctrl+v就好)
觉得唯一有点难度的就是怎么把序列还原成树的形态
dfs,记一个bh(常函数)
bh只加不减,表示序列中的指针右移
这里写代码片
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int N=500001;
char s[N];
int f[N][3],g[N][3],fa[N<<1],bh,ch[N][2];
void dfs(int faa)
{
bh++; //当前位置
ch[faa][ch[faa][0] ? 1:0]=bh;
fa[bh]=faa;
int x=s[bh-1]-'0';
int r=bh; //局部变量,保证儿子能精准的找到爸爸
if (x==2) //两个儿子
{
dfs(r);
dfs(r);
}
else if (x==1)
{
dfs(r);
}
else return;
}
void doit(int now)
{
if (ch[now][0]) doit(ch[now][0]); //dp son
if (ch[now][1]) doit(ch[now][1]);
if (!ch[now][0]&&!ch[now][1]) //leave
{
f[now][0]=0;f[now][1]=0;f[now][2]=1; //two means G
g[now][0]=0;g[now][1]=0;g[now][2]=1; //two means G
return;
}
else if (ch[now][0]&&ch[now][1]) //two sons
{
f[now][0]=max(f[ch[now][0]][2]+f[ch[now][1]][1],f[ch[now][0]][1]+f[ch[now][1]][2]);
f[now][1]=max(f[ch[now][0]][2]+f[ch[now][1]][0],f[ch[now][0]][0]+f[ch[now][1]][2]);
f[now][2]=max(f[ch[now][0]][0]+f[ch[now][1]][1],f[ch[now][0]][1]+f[ch[now][1]][0])+1;
g[now][0]=min(g[ch[now][0]][2]+g[ch[now][1]][1],g[ch[now][0]][1]+g[ch[now][1]][2]);
g[now][1]=min(g[ch[now][0]][2]+g[ch[now][1]][0],g[ch[now][0]][0]+g[ch[now][1]][2]);
g[now][2]=min(g[ch[now][0]][0]+g[ch[now][1]][1],g[ch[now][0]][1]+g[ch[now][1]][0])+1;
}
else if (ch[now][0])
{
f[now][0]=max(f[ch[now][0]][2],f[ch[now][0]][1]);
f[now][1]=max(f[ch[now][0]][2],f[ch[now][0]][0]);
f[now][2]=max(f[ch[now][0]][0],f[ch[now][0]][1])+1;
g[now][0]=min(g[ch[now][0]][2],g[ch[now][0]][1]);
g[now][1]=min(g[ch[now][0]][2],g[ch[now][0]][0]);
g[now][2]=min(g[ch[now][0]][0],g[ch[now][0]][1])+1;
}
else
{
f[now][0]=max(f[ch[now][1]][2],f[ch[now][1]][1]);
f[now][1]=max(f[ch[now][2]][2],f[ch[now][1]][0]);
f[now][2]=max(f[ch[now][2]][0],f[ch[now][1]][1])+1;
g[now][0]=min(g[ch[now][1]][2],g[ch[now][1]][1]);
g[now][1]=min(g[ch[now][2]][2],g[ch[now][1]][0]);
g[now][2]=min(g[ch[now][2]][0],g[ch[now][1]][1])+1;
}
}
int main()
{
scanf("%s",&s);
bh=0;
dfs(0); //还原树的形态
doit(1);
int f1=max(f[1][0],max(f[1][1],f[1][2]));
int f2=min(g[1][0],min(g[1][1],g[1][2]));
printf("%d %d",f1,f2);
return 0;
}