BZOJ-1864-[Zjoi2006]三色二叉树(树形dp)

Description

Input

仅有一行,不超过500000个字符,表示一个二叉树序列。

Output

输出文件也只有一行,包含两个数,依次表示最多和最少有多少个点能够被染成绿色。

Sample Input

1122002010

Sample Output

5 2

HINT

Source

Day1

题解

这道题我们考虑dp

我们先把树给构造出来(可以用栈,也可以用dfs)

建完树后,我们用f[i][0/1/2][0]表示i节点填绿/蓝/红色的最小答案,f[i][0/1/2][1]表示i节点填绿/蓝/红色的最大答案

我们考虑i节点从两个儿子转移

f[i][0][0]=min(f[s1][1][0]+f[s2][2][0],f[s1][2][0]+f[s2][1][0])

f[i][1][0]=min(f[s1][0][0]+f[s2][2][0],f[s1][2][0]+f[s2][0][0])

f[i][2][0]=min(f[s1][0][0]+f[s2][1][0],f[s1][1][0]+f[s2][0][0])

f[i][0/1/2][1]转移同理

 1 #include<bits/stdc++.h>
 2 #define N 500005
 3 using namespace std;
 4 int tot,top;
 5 int Stack[N];
 6 int f[N][3][2];
 7 char s[N];
 8 int main(){
 9     scanf("%s",s+1);
10     int len=strlen(s+1);
11     for (int i=len;i>=1;i--)
12         if (s[i]==‘2‘){
13             int x=Stack[top],y=Stack[--top];
14             tot++;
15             f[tot][0][0]=min(f[x][1][0]+f[y][2][0],f[x][2][0]+f[y][1][0])+1;
16             f[tot][1][0]=min(f[x][2][0]+f[y][0][0],f[x][0][0]+f[y][2][0]);
17             f[tot][2][0]=min(f[x][1][0]+f[y][0][0],f[x][0][0]+f[y][1][0]);
18             f[tot][0][1]=max(f[x][1][1]+f[y][2][1],f[x][2][1]+f[y][1][1])+1;
19             f[tot][1][1]=max(f[x][2][1]+f[y][0][1],f[x][0][1]+f[y][2][1]);
20             f[tot][2][1]=max(f[x][1][1]+f[y][0][1],f[x][0][1]+f[y][1][1]);
21             Stack[top]=tot;
22         } else
23         if (s[i]==‘1‘){
24             int x=Stack[top];
25             tot++;
26             f[tot][0][0]=min(f[x][1][0],f[x][2][0])+1;
27             f[tot][1][0]=min(f[x][0][0],f[x][2][0]);
28             f[tot][2][0]=min(f[x][0][0],f[x][1][0]);
29             f[tot][0][1]=max(f[x][1][1],f[x][2][1])+1;
30             f[tot][1][1]=max(f[x][0][1],f[x][2][1]);
31             f[tot][2][1]=max(f[x][0][1],f[x][1][1]);
32             Stack[top]=tot;
33         } else{
34             tot++;
35             f[tot][0][0]=f[tot][0][1]=1;
36             Stack[++top]=tot;
37         }
38     int Max=max(f[tot][0][1],max(f[tot][1][1],f[tot][2][1]));
39     int Min=min(f[tot][0][0],min(f[tot][1][0],f[tot][2][0]));
40     printf("%d %d",Max,Min);
41     return 0;
42 } 

时间: 2024-11-05 22:42:14

BZOJ-1864-[Zjoi2006]三色二叉树(树形dp)的相关文章

BZOJ1864[ZJOI2006]三色二叉树[树形DP]

1864: [Zjoi2006]三色二叉树 Time Limit: 1 Sec  Memory Limit: 64 MBSubmit: 773  Solved: 548[Submit][Status][Discuss] Description Input 仅有一行,不超过500000个字符,表示一个二叉树序列. Output 输出文件也只有一行,包含两个数,依次表示最多和最少有多少个点能够被染成绿色. Sample Input 1122002010 Sample Output 5 2 HINT

BZOJ1864 [Zjoi2006]三色二叉树

简单地树形DP 我们用f,g表示最大.最小值,0,1,2表示颜色然后直接推 递推公式请见程序233 1 /************************************************************** 2 Problem: 1864 3 User: rausen 4 Language: C++ 5 Result: Accepted 6 Time:24 ms 7 Memory:19244 kb 8 ***********************************

luogu 2585 [ZJOI2006]三色二叉树

输入格式 输入文件名:TRO.IN 输入文件仅有一行,不超过500000个字符,表示一个二叉树序列. 输出格式 输出文件名:TRO.OUT 输出文件也只有一行,包含两个数,依次表示最多和最少有多少个点能够被染成绿色. 输入输出样例 输入 #1复制 1122002010 输出 #1复制 5 2 分析 树形DP,父子关系已经给出了,直接按顺序搜就是 只是需要记录儿子个数以便确定编号位置 dp的部分比较简单,dp[节点][颜色] = 绿色的个数 1 /*************************

BZOJ_1864_[Zjoi2006]三色二叉树_树形DP

题意: 分析:递归建树,然后DP,从子节点转移. 注意到红色和蓝色没有区别,因为我们可以将红蓝互换而方案是相同的.这样的话我们只需要知道当前节点是否为绿色即可. 代码: 1 #include <stdio.h> 2 #include <string.h> 3 #include <algorithm> 4 using namespace std; 5 #define N 500050 6 int lson[N],rson[N],cnt,n; 7 int f[N][2],g

ZJOI2006 三色二叉树

Luogu orz 十分钟切掉的 M_sea 巨佬 蒟蒻用的是一种比较蠢的状态... \(0\) 表示绿色 设 \(dp[i,color]\) 为第 \(i\) 个点被标成 \(color\) 的子树最优解. 然后转移的时候只要枚举一下儿子的颜色即可. 方程懒得写了... 总而言之还是 \(O(n)\) 的辣,但是常数巨大 #include <iostream> #include <cstdio> #include <cstring> const int max_n =

【题解】 bzoj1864: [Zjoi2006]三色二叉树 (动态规划)

bzoj1864,懒得复制,戳我戳我 Solution: 其实想出来了\(dp\)方程推出来了最大值,一直没想到推最小值 \(dp[i][1/0]\)表示\(i\)号节点的子树中的绿色染色最大值,\(1\)表示该节点染色,\(0\)表示该节点不染色 \[dp[i][1]=dp[ls][0]+dp[rs][0]+1\] \[dp[i][0]=max(dp[ls][1]+dp[rs][0],dp[rs][1]+dp[ls][0])\] \(f[i][1/0]\)表示存的最小值,状态同上 \[f[i]

P2585 [ZJOI2006]三色二叉树

介绍一个无建树做法 个人认为我的代码比较易懂(简直不需要注释) 定义dp[x][0/1/2] 分别为x节点染绿 /红 /蓝 情况下子树中最多有几个点被染成绿色 类似的 f[x][0/1/2] 为最少有几个点 见代码: #include<iostream> #include<cstdio> #include<cstring> using namespace std; const int N = 500050; char s[N]; int dp[N][4], f[N][4

多叉树转二叉树+树形dp(codevs 1746 贪吃的九头龙 2002noi)

题目传送门 看到这个题目我们要先把问题简化了,条件中是多叉树,我们可以把它转换成二叉树,左边是儿子右边是兄弟的储存方式. 首先先判断否的部分,当总的果子小于需求,也就是N-k<M-1时输出-1. 我们再判断是的部分 如果没有大头,一定存在难受值为0的方案但是现在题目中有大头,我们就可以按按照小头的个数进行分类 1.有一个小头,我们要考虑小头和大头的难受值之和. 2.有多个小头,因为小头可以在奇偶的进行变换,所以我们只需要考虑大头的难受值. 分析到这里,我们就可以发现是树形dp我们设f[i][j]

bzoj 1017[JSOI2008]魔兽地图DotR - 树形dp

1017: [JSOI2008]魔兽地图DotR Time Limit: 30 Sec  Memory Limit: 162 MB Description DotR (Defense of the Robots) Allstars是一个风靡全球的魔兽地图,他的规则简单与同样流行的地图DotA (Defense of the Ancients) Allstars.DotR里面的英雄只有一个属性--力量.他们需要购买装备来提升自己的力量值,每件装备都可以使佩戴它的英雄的力量值提高固定的点数,所以英雄

BZOJ 1907 树的路径覆盖 树形DP

题目大意:给定一棵树,求最小路径覆盖 数据范围1W,看到还想跑网络流来着= = 不过算了明明树形DP这么水还是不要用网络流这种大杀器为好 首先将所有的链都考虑成以链上所有点的LCA为转折点的V字形 那么点有两种:转折点和非转折点 因此我们选择两种状态进行转移:还会和父亲组成链的状态和成为转折点的状态 转移就自己YY算了 时间复杂度是线性的 #include <cstdio> #include <cstring> #include <iostream> #include