二叉树??树状dp??NONONO!!!
本题的树不固定,他要求去找出来一个最优的树,所以不适合使用树状dp去进行求解。但又因为题中所给的有中序遍历的序列,中序遍历序列最大的特点在于定根可将区间分成左右子树。
那么分成两部分之后就可以分别去计算这两部分,也就是在这两小部分里面取找根。
那么可以得到dp[i][j]为i,j这个区间组成的树的最高加分。
得到状态转移方程为:dp[i][j] = max(dp[i][k], dp[k+1][j])。
对于前序遍历:在每一个区间树遍历最高加分的时候去记录最优的那个根。然后重新dfs遍历得到就行。
那么可以得到dp[i][j]为i,j这个区间组成的树的最高加分。
得到状态转移方程为:dp[i][j] = max(dp[i][k], dp[k+1][j])。
对于前序遍历:在每一个区间树遍历最高加分的时候去记录最优的那个根。然后重新dfs遍历得到就行。
//题目中所给的是一个中序遍历的序列,那么只要定下一个根就可以将这个序列分成左右两部分。
//分成两部分之后就可以分别去计算这两部分,也就是在这两小部分里面取找根。
//那么可以得到dp[i][j]为i,j这个区间组成的树的最高加分。
//得到状态转移方程为:dp[i][j] = max(dp[i][k], dp[k+1][j])。
//对于前序遍历:在每一个区间树遍历最高加分的时候去记录最优的那个根。然后重新dfs遍历得到就行。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 33;
int n;
int a[maxn];
int dp[maxn][maxn];
int zhong[maxn][maxn];
void dfs(int l, int r)
{
if (l==r)
{
cout<<l<<' ';
return ;
}
if (l>r) return ;
int mid = zhong[l][r];
int l1 = l;
int r1 = mid-1;
int l2 = mid+1;
int r2 = r;
cout<<mid<<" ";
dfs(l1, r1);dfs(l2, r2);
}
int main()
{
cin>>n;
for (int i=1;i<=n;i++) cin>>a[i];
for (int len = 1;len<=n;len++)
{
for (int l = 1;l<=n-len+1;l++)
{
int r = l+len-1;
if (len==1)
dp[l][r] = a[l];
else{
for (int k=l;k<=r;k++)
{
int num = (l<=k-1? dp[l][k-1]:1) * (k+1<=r? dp[k+1][r]:1) + dp[k][k];
if (dp[l][r]<num)
{
dp[l][r] = num;
zhong[l][r] = k;
}
}
}
}
}
cout<<dp[1][n]<<endl;
//通过之前记录的来进行dfs输出前序遍历
dfs(1, n);
return 0;
}

京公网安备 11010502036488号