原题链接
ACwing
思路
如果只知道一棵树的中序遍历,无法确定这一棵树的构造;不过,我们可以通过假定各个子树的根,从中序遍历中构造出一颗符合条件的树(有多少种可能实际上也可以通过动态规划求出)。
如果我们选定了一个根,其子树的最大值与该根无关,换而言之,问题具有最优子结构。自然而然的,我们应该使用一个中序遍历的区间作为状态(唯一确定一个最大值),原问题实际上就变成了一个区间DP 问题。
由于此处需要我们重构一棵树,所以保存每一个区间的最优节点,这样就可以通过dfs还原树。
实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
| #include <bits/stdc++.h> using namespace std;
const int N = 40; int dp[N][N]; int best[N][N]; int val[N];
int solve(int arrlen){ memset(dp,0,sizeof dp); for (int len =1;len<=arrlen;len++){ for(int i=1;i+len-1<=arrlen;i++){ int j = i+len-1; if(len==1){ dp[i][i] = val[i]; continue; } int maxv = -1; for(int k=i;k<=j;k++){ int root = val[k]; int left=1; if(k-1>=i)left = dp[i][k-1]; int right =1; if(k+1<=j)right = dp[k+1][j]; int tem = root + left*right; if(tem>maxv){ best[i][j] = k; maxv = tem; } } dp[i][j] = maxv; } } return dp[1][arrlen]; }
void build_tree(int l, int r,vector<int>&q){ if(l>r)return; if(l==r){ q.push_back(l); return; } int best_root = best[l][r]; q.push_back(best_root); build_tree(l,best_root-1,q); build_tree(best_root+1,r,q); }
int main(){ int n; cin>>n; for(int i=1;i<=n;i++)cin>>val[i]; vector<int>pre_order; cout<<solve(n)<<endl; build_tree(1,n,pre_order); for(int i=0;i<pre_order.size();i++){ if(i)cout<<" "; cout<<pre_order[i]; } return 0; }
|
感谢阅读!欢迎评论嗷~