P1040 加分二叉树

链接:https://www.luogu.com.cn/problem/P1040

题意:题目给出了中序遍历(左根右)为1~n的序列,要我们构造出一颗树,满足最后的结果最大

思路:根据中序遍历的性质,在一个连续的区间(L,R)里,哪一个数当这段区间的根都是可能的

   于是,我们可以采用区间DP的方法,从小开始枚举

   先将只有一个数的情况初始话,然后再将区间从小到大枚举,在枚举区间时,再枚举哪个点当root最好即可

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const int maxn=35;
 5 ll dp[maxn][maxn];
 6 int root[maxn][maxn];
 7 void solve(int l,int r)
 8 {
 9     if(l>r) return;
10     printf("%d ",root[l][r]);
11     if(l==r) return;
12     int mid=root[l][r];
13     solve(l,mid-1);
14     solve(mid+1,r);
15 }
16 int main()
17 {
18     int n;
19     scanf("%d",&n);
20     for(int i=1;i<=n;i++){
21         scanf("%d",&dp[i][i]);
22         root[i][i]=i;
23     }
24     for(int len=1;len<n;len++){  //枚举区间大小
25         for(int i=1;i+len<=n;i++){  
26             int j=i+len;   //i为区间左端点,j为区间右端点
27             dp[i][j]=dp[i+1][j]+dp[i][i];  //先将特殊情况给记录下来(以i为根时,左区间为空)
28             root[i][j]=i;                 //空时定为数值1
29             for(int k=i+1;k<j;k++){
30                 if(dp[i][j]<dp[i][k-1]*dp[k+1][j]+dp[k][k]){
31                     dp[i][j]=dp[i][k-1]*dp[k+1][j]+dp[k][k];
32                     root[i][j]=k;
33                 }
34             }
35         }
36     }
37     printf("%lld\n",dp[1][n]);
38     solve(1,n);   //按先序遍历的方式输出;
39 }

 

posted @ 2020-03-18 15:39  古比  阅读(115)  评论(0编辑  收藏  举报