洛谷 P1040 加分二叉树 & [NOIP2003提高组](区间dp,树的遍历)

传送门


解题思路

对于整个中序遍历,做一遍区间dp:

枚举区间[l...r]内的所有节点作为根节点,然后计算出得分,若比当前的值要大,同时更新dp值和root[l][r](为了输出先序遍历)。

先序是根左右,所以递归输出就好了。

AC代码

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 using namespace std;
 5 int n,a[35],dp[35][35],root[35][35];
 6 void print(int l,int r){ 
 7     if(l>r) return;
 8     if(l==r) printf("%d ",l);
 9     else{
10         printf("%d ",root[l][r]);
11         print(l,root[l][r]-1);
12         print(root[l][r]+1,r);
13     }
14 }
15 int main()
16 {
17     cin>>n;
18     for(int i=1;i<=n;i++) cin>>a[i];
19     for(int i=1;i<=n;i++) dp[i][i]=a[i];
20     for(int i=1;i<=n;i++){
21         for(int j=0;j<i;j++) dp[i][j]=1;
22     }
23     for(int len=2;len<=n;len++){
24         for(int i=1;i<=n;i++){
25             int j=i+len-1;
26             for(int k=i;k<=j;k++){
27                 if(dp[i][j]<dp[i][k-1]*dp[k+1][j]+a[k]){
28                     dp[i][j]=dp[i][k-1]*dp[k+1][j]+a[k];
29                     root[i][j]=k;
30                 }
31             }
32         }
33     }
34     cout<<dp[1][n]<<endl;
35     print(1,n);
36     return 0;
37 }

//NOIP2003提高组 t3

posted @ 2020-02-24 19:31  尹昱钦  阅读(154)  评论(0编辑  收藏  举报