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 ****************************************************************/
 9
10 #include <cstdio>
11 #include <algorithm>
12
13 #define Rep(i, n) for (i = 0; i < n; ++i)
14 using namespace std;
15 const int inf = (int) 1e9;
16 const int N = 500005;
17
18 int cnt, s[N][3], f[N][3], g[N][3];
19
20 void dfs(int p) {
21     int i, j, k;
22     s[p][0] = getchar() - ‘0‘;
23     if (!s[p][0]) {
24         f[p][0] = g[p][0] = 1;
25         return;
26     }
27     for (i = 1; i <= s[p][0]; ++i) {
28         s[p][i] = ++cnt;
29         dfs(cnt);
30     }
31     g[p][0] = g[p][1] = g[p][2] = inf;
32     if (s[p][0] == 1) {
33         Rep(i, 3) Rep(j, 3)
34             if (i != j)
35                 f[p][i] = max(f[p][i], f[s[p][1]][j] + !i),
36                 g[p][i] = min(g[p][i], g[s[p][1]][j] + !i);
37     } else {
38         Rep(i, 3) Rep(j, 3) Rep(k, 3)
39             if (i != j && j != k && i != k)
40                 f[p][i] = max(f[p][i], f[s[p][1]][j] + f[s[p][2]][k] + !i),
41                 g[p][i] = min(g[p][i], g[s[p][1]][j] + g[s[p][2]][k] + !i);
42     }
43 }
44
45 int main() {
46     dfs(cnt = 1);
47     printf("%d %d\n", max(max(f[1][0], f[1][1]), f[1][2]), min(min(g[1][0], g[1][1]), g[1][2]));
48     return 0;
49 }

时间: 2024-10-05 23:58:50

BZOJ1864 [Zjoi2006]三色二叉树的相关文章

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]三色二叉树 (动态规划)

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]

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 =

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

bzoj1864 三色二叉树

Description Input 仅有一行,不超过500000个字符,表示一个二叉树序列. Output 输出文件也只有一行,包含两个数,依次表示最多和最少有多少个点能够被染成绿色. 记录每个节点染成每种颜色时以此节点为根的子树中绿色节点个数的最大值和最小值 信息由叶节点向上传递 #include<cstdio> int n; int p=0,mxv=0,mnv=2147483647; int m3[]={0,1,2,0,1,2}; char s[500005]; int cmax[5000

ZJOI2016 三色二叉树

首先 此题给出的时一个可以代表二叉树的一个序列 直接递归把树建出来就好了. 然后考虑DP. 比较容易想到的是一个f[i][3]的DP,分别代表以i为根时,i染三种颜色的最大数目. 直接根据限制转移即可,但代码比较长. 考虑(代码)简单一点的, 实际上,由于我们只在意绿色的染了多少,所以染其他两种色没有区别(也就是可以完全互相转换). 所以考虑是否可以设f[i][2],分别代表以i为根时,i染或不染绿色的最大数目. 同样直接根据限制转移. #include <bits/stdc++.h> #de

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节点填