首页 > 其他 > 详细

加分二叉树

时间:2017-09-25 00:37:21      阅读:374      评论:0      收藏:0      [点我收藏+]

原题链接:https://www.luogu.org/problem/show?pid=1040

刚拿到这道题的我是懵逼的,因为刚开始除了暴力我完全想不到从哪入手。

其实这题是一个区间dp和dfs,代码还是挺简单的。

参考了一篇题解,对那位大佬表示由衷的敬意。

设f[i][j]表示在区间(i,j)内的最大加分,那么有f[i][j] = max(f[i][k-1]*f[k+1][j]+a[k]) ,a[k]代表第i个点的分数,k是枚举的根节点,即状态转移方程的那个式子是指的在区间(i,j)上的以k为根节点的最大分数。

还记得区间dp的基本思路吗?由小区间推出大区间,这题也是这样,i从n倒推至1,j从i正推至n,而中间的枚举根节点k的范围是[i,j]。

同时我们还需要一个数组n[i][j]表示在区间(i,j)加分最大时的根节点,在后面会用到。

最高加分便是f[1][N]。//为了不和n数组重复用一个大写

考虑下一个问题,如何输出一棵树的前序遍历?

还记得什么是前序遍历吗?先根,再左子树,再右子树。

要输出一个遍历,递归输出就好。首先输出当前的点(根节点),然后输出左子树,再输出右子树,简单的划分。

参考代码:

 1 #include <iostream>
 2 #define maxn 35
 3 using namespace std;
 4 int a[maxn];
 5 int N;
 6 int f[maxn][maxn];
 7 int n[maxn][maxn];
 8 
 9 
10 void dfs(int l,int r){
11     if (l>r)
12         return;
13     int mid = n[l][r];
14     cout << mid << " ";
15     dfs(l,mid-1);
16     dfs(mid+1,r);
17 }
18 
19 int main(){
20     cin >> N;
21     for (int i=0;i<=N;i++)
22         for (int j=0;j<=N;j++)
23             f[i][j] = 1;
24 
25     for (int i=1;i<=N;i++){
26         cin >> a[i];
27         f[i][i] = a[i];
28         n[i][i] = i;
29     }
30 
31     for (int i=N-1;i>=1;i--)
32         for (int j=i+1;j<=N;j++)
33             for (int k=i;k<=j;k++)
34                 if (f[i][k-1]*f[k+1][j]+a[k]>f[i][j]){
35                     n[i][j]=k;
36                     f[i][j]=f[i][k-1]*f[k+1][j]+a[k];
37                 }
38     cout << f[1][N] << endl;
39     dfs(1,N);
40 
41     return 0;
42 }

 

加分二叉树

原文:http://www.cnblogs.com/OIerShawnZhou/p/7589419.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!