P1040题解
题目链接
这是一道区间DP题,当然你说他是树形DP题也行.因为这道题给的是中序遍历,所以说分清左右子树是很容易的,这为我们使用DP创造了机会. 这里我们假设dp[i][j]表示给出的序列中i到j最大的值.由于是中序遍历,只要这一串是子树那么无论哪个元素是根结点都可以.
因此状态转移方程为
我们用区间DP简单实现即可.这里注意dp[i][i]的值就是a[i].
同时为了输出前序遍历我们记录一下每一段的根节点(root)
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=35;
int n,a[N],dp[N][N],root[N][N];
void work(int l, int r){if(l>r) return;cout<<root[l][r]<<' ';if(l==r) return;work(l,root[l][r]-1);work(root[l][r]+1,r);
}
signed main(){cin>>n;for(int i=1;i<=n;i++) cin>>a[i];for(int i=1;i<=n;i++) root[i][i]=i, dp[i][i-1]=1, dp[i][i]=a[i];for(int len=2;len<=n;len++){for(int i=1;i+len-1<=n;i++){int j=i+len-1;dp[i][j]=dp[i+1][j]+a[i], root[i][j]=i;for(int k=i+1;k<j;k++){if(dp[i][j]<dp[i][k-1]*dp[k+1][j]+a[k]){dp[i][j]=dp[i][k-1]*dp[k+1][j]+a[k];root[i][j]=k;}}}}cout<<dp[1][n]<<endl, work(1,n);return 0;
}