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 }