其他分享
首页 > 其他分享> > 动态规划:P2585[ZJOI2006]三色二叉树

动态规划:P2585[ZJOI2006]三色二叉树

作者:互联网

P2585[ZJOI2006]三色二叉树 题目传送门:P2585 [ZJOI2006]三色二叉树 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 题目: 思路分析: 可以借鉴动态规划:P1352没有上司的舞会 - 朱朱成 - 博客园 (cnblogs.com),建立一个二维的dp 第二维01代表有没有去,有没有染成绿色的。对于一个结点来说,以这个结点为根的子树,染成绿色的数目,因为是二叉树,所以一个结点只会连两个结点,所以不染成绿色的就等于max(左子节点染成绿色,的左子树绿色数目总和,右子节点不染成绿色,的右子树绿色数目总和),因为不染成绿色,左右子节点必有一个染成绿色,取最优就行,因为是三种颜色,所以不可能父节点不成绿色,两个子节点也不是绿色,可以根据抽屉原理得知。然后其他的计算其实跟其他两种颜色没关系了,就考虑染不染成绿色。然后我们再计算这个点染成绿色,就等于左子节点不染成绿色,的左子树绿色数目总和+右子节点不染成绿色,的右子树绿色数目总和+1。注意+1,就是父节点刚染成绿色的1。然后利用DFS,按照这个思路树形DP即可。因为题目是求最多和最少的,所以构建两个DP数组,max改成min即可。
关键DP代码:   

 

 

 

 

AC完整代码:   
 1 #include <cstring>
 2 #include <cmath>
 3 #include <cstdio>
 4 #include<iostream>
 5 using namespace std;
 6 const int maxn = 5 * 1e5 + 5;
 7 //设tree[i][0] 为第i个节点的左节点编号
 8 //设tree[i][1] 为第i个节点的右节点编号
 9 //dp[i][0]为第i个节点 为根 并且这个结点涂绿色 的子树 绿色最多的数量
10 //dp[i][12]为第i个节点 为根 并且这个结点不涂绿色 的子树 绿色最多的数量
11 int dp1[maxn][2];//一个求max 一个求min
12 int dp2[maxn][2];
13 int tree[maxn][2];
14 int cnt;
15 string str;
16 void dfs(int root)
17 {
18     cnt++;//表示访问了x个点
19     if (str[root] == '0')
20         return;
21     if (str[root] == '1')
22     {
23         tree[root][0] = root + 1;//如果有只有一个子节点 一定是左边结点 并且就是下一个root+1
24         dfs(root + 1);//搜索下一个点
25     }
26     else if (str[root] == '2')
27     {
28         tree[root][0] = root + 1;
29         dfs(root + 1);
30         tree[root][1] = cnt + 1;//右结点就是访问的点数+1
31         dfs(cnt + 1);
32     }
33 }
34 
35 void dp_dfs1(int x)
36 {
37     if (x == 0)//如果只有一个子节点的点 他的邻接点就是默认为0 搜到这些点直接return
38     {
39         return;
40     }
41     if (str[x] == '0')//如果是叶子
42     {
43         dp1[x][0] = 1;
44         return;
45     }
46     else
47     {
48         dp_dfs1(tree[x][0]);
49         dp_dfs1(tree[x][1]);
50         dp1[x][0] = dp1[tree[x][0]][1] + dp1[tree[x][1]][1]+1;//结点染绿色就等于左右两边不染的颜色+1
51         //cout << x << " " << "左边" << ":" << dp[x][0] << " " << endl;
52         dp1[x][1] = max(dp1[tree[x][0]][0] + dp1[tree[x][1]][1], dp1[tree[x][0]][1] + dp1[tree[x][1]][0]);
53         //cout << x << " " << "右边" << ":" << dp[x][1] << " " << endl;
54     }
55 }
56 void dp_dfs2(int x)
57 {
58     if (x == 0)//如果只有一个子节点的点 他的邻接点就是默认为0 搜到这些点直接return
59     {
60         return;
61     }
62     if (str[x] == '0')//如果是叶子
63     {
64         dp2[x][0] = 1;
65         return;
66     }
67     else
68     {
69         dp_dfs2(tree[x][0]);
70         dp_dfs2(tree[x][1]);
71         dp2[x][0] = dp2[tree[x][0]][1] + dp2[tree[x][1]][1] + 1;//结点染绿色就等于左右两边不染的颜色+1
72         //cout << x << " " << "左边" << ":" << dp[x][0] << " " << endl;
73         dp2[x][1] = min(dp2[tree[x][0]][0] + dp2[tree[x][1]][1], dp2[tree[x][0]][1] + dp2[tree[x][1]][0]);
74         //cout << x << " " << "右边" << ":" << dp[x][1] << " " << endl;
75     }
76 }
77 int main()
78 {
79     cin >> str;
80     for (int i = str.length(); i >= 1; --i)
81     {
82         str[i] = str[i - 1];
83     }
84     dfs(1);
85     dp_dfs1(1);
86     dp_dfs2(1);
87     cout << max(dp1[1][0], dp1[1][1]);
88     cout << " ";
89     cout << min(dp2[1][0], dp2[1][1]);
90     return 0;
91 
92 }

 

 

标签:染成,tree,绿色,P2585,二叉树,str,ZJOI2006,root,节点
来源: https://www.cnblogs.com/zhuzhucheng/p/16245078.html