ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

动态规划:P1040[NOIP2003 提高组] 加分二叉树 树形DP

2022-05-05 10:34:36  阅读:170  来源: 互联网

标签:结点 NOIP2003 int P1040 maxn 二叉树 root find dp


P1040[NOIP2003 提高组] 加分二叉树 题目传送门:P1040 [NOIP2003 提高组] 加分二叉树 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 题目:

 

思路:

  题目给的是中序遍历,所以一定是根左右,在序列中,对于每一个结点,他左边的数字可能就是他的左结点,或者左子树为空,右边的数字可能就是他的右结点,或者右子树为空,右边的数字跟他没关系。所以我们可以先看每一个点,对于每一个点来说,以他自己为一棵树,左子树右子树均为空的加分就是他的点权,可以通过题目的加分计算方法得知。我们先构建dp[i][j] 数组 dpi j 就代表以i为树的最左边的点,j为树的最右边的点构造树,因为是中序遍历 左根右。由刚刚推导的一个点为树的情况,dp[i][i]就都等于点权,所以初始化的时候,不需要再构建点权数组,直接初始化在dp[i][i],然后我们寻求状态转移,对于下一个状态,也就是树里面只有两个点的情况,我们的思路就是从树只有一个点推到树序列的总长度,有点吧这一题转化为区间DP了,因为他给的中序序列构造出来的树是任意的,无法用构造树以后去做。那么对于区间长度为2的dp[l][r],先初始化为dp[l+1][r]+dp[l][l];//默认左子树为空,然后进行切割,也就是对于这个区间,在中间选取一个结点做根,因为是中序遍历,根左右,但是对于长度为2的点,无法切割,选根其实只能从长度为3的开始,因为根左右,主要是长度为2的点没必要切割,他默认左树为空和右子树为空,和初始化的值是一样的,切割也就这两种情况,没有必要,然后就从2一直推到n,但是要求前序遍历,根左右,每一次切割找到更好地根就记录root[i][j]=k k就是最好的根,我们构建这个root就是存区间为i j 时最优的根k,然后递归寻找路径,或者前序序列。构造一个find函数,每次传入区间的l and r,输出根root [l][r],因为是前序序列,所以再find中再递归调用find查找左区间和有区间,find l k-1,and find k+1 r  注意递归返回条件 当l==r 时,就输出l 因为是以自己为根 这就是叶子结点,l>r 就直接return,边界条件。

  关键DP代码:

 

 

 

find函数:

 

 

完整AC代码:

 1 #include<iostream>
 2 using namespace std;
 3 typedef long long ll;
 4 const int maxn = 50;
 5 ll dp[maxn][maxn];
 6 int root[maxn][maxn];
 7 int n;
 8 void find(int l,int r)
 9 {
10     if (l == r)
11     {
12         cout << root[l][r]<<" ";
13         return;
14     }
15     if (l > r)
16         return;
17     int head = root[l][r];
18     cout << head << " ";
19     find(l, head - 1);
20     find(head+1,r );
21 }
22 int main()
23 {
24     cin >> n;
25     for (int i = 1; i <= n; ++i)
26     {
27         cin >> dp[i][i];
28         root[i][i] = i;
29         // dp[i][i-1]=1;
30     }
31     for (int len = 1; len <= n; ++len)
32     {
33         for (int l = 1; l + len - 1 <= n; ++l)
34         {
35             int r = l + len - 1;
36             dp[l][r] = dp[l + 1][r] + dp[l][l];//默认左子树为空
37             root[l][r] = l;
38             for (int k = l + 1; k <= r - 1; ++k)//对于这个循环 只能三个以上的开始切割
39             {
40                 if (dp[l][r] < dp[l][k - 1] * dp[k + 1][r] + dp[k][k])
41                 {
42                     dp[l][r] = dp[l][k - 1] * dp[k + 1][r] + dp[k][k];
43                     root[l][r] = k;
44                 }
45                
46             }
47         }
48     }
49     cout << dp[1][n]<<endl;
50     find(1, n);
51     return 0;
52 }

 

 

 

  

 

标签:结点,NOIP2003,int,P1040,maxn,二叉树,root,find,dp
来源: https://www.cnblogs.com/zhuzhucheng/p/16223751.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有