1864: [Zjoi2006]三色二叉树
Time Limit: 1 Sec Memory Limit: 64 MB Submit: 662 Solved: 472
[Submit][Status][Discuss] Description
Input仅有一行,不超过500000个字符,表示一个二叉树序列。
Output
输出文件也只有一行,包含两个数,依次表示最多和最少有多少个点能够被染成绿色。
Sample Input
1122002010
Sample Output
5 2
HINT
Source
Day1
树形DP,不难
f[i][j]表示i节点颜色为j的最小花费。 2为绿色。
一个孩子时:f[i][0]=max(f[son[i]][1],f[son[i]][2]);
f[i][1]=max(f[son[i]][0],f[son[i]][2]);
f[i][2]=max(f[son[i]][1],f[son[i]][0])+1;
两个时: f[i][0]=max(f[ls[i]][1]+f[rs[i]][2],f[ls[i]][2]+f[rs[i]][1]);
f[i][1]=max(f[ls[i]][0]+f[rs[i]][2],f[ls[i]][2]+f[rs[i]][0]);
f[i][2]=max(f[ls[i]][1]+f[rs[i]][0],f[ls[i]][0]+f[rs[i]][1])+1;
输入不好处理呦,我用的递归?!
代码:
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<iostream>
const int maxn = 500010;
using namespace std;
struct tree
{
int sum;
int son[3];
}node[maxn];
int tot;
int f[maxn][3];
int g[maxn][3];
int my_min(int x,int y,int z)
{
return min(min(x,y),z);
}
int my_max(int x,int y,int z)
{
return max(max(x,y),z);
}
int read()
{
tot++;
int id=tot;
char c=getchar();
c=c-'0';
for(int i=1;i<=c;i++)
{
node[id].sum++;
node[id].son[i]=read();
}
return id;
}
void dp(int x)
{
int s=node[x].sum;
int u=node[x].son[1];
int v=node[x].son[2];
if(u) dp(u);
if(v) dp(v);
if(s==1)
{
f[x][0]=min(f[u][1],f[u][2]);
f[x][1]=min(f[u][0],f[u][2]);
f[x][2]=min(f[u][1],f[u][0]);
g[x][0]=max(g[u][1],g[u][2]);
g[x][1]=max(g[u][0],g[u][2]);
g[x][2]=max(g[u][1],g[u][0]);
}
if(s==2)
{
f[x][0]=min(f[u][1]+f[v][2],f[u][2]+f[v][1]);
f[x][1]=min(f[u][0]+f[v][2],f[u][2]+f[v][0]);
f[x][2]=min(f[u][1]+f[v][0],f[u][0]+f[v][1]);
g[x][0]=max(g[u][1]+g[v][2],g[u][2]+g[v][1]);
g[x][1]=max(g[u][0]+g[v][2],g[u][2]+g[v][0]);
g[x][2]=max(g[u][1]+g[v][0],g[u][0]+g[v][1]);
}
f[x][2]++;
g[x][2]++;
}
int main()
{
read();
dp(1);
printf("%d %d",my_max(g[1][0],g[1][1],g[1][2]),my_min(f[1][0],f[1][1],f[1][2]));
return 0;
}