思路:因为中序遍历已知,所以找到根以后就可以递归的处理问题了。
定义dp[i][j]表示中序遍历i到j的子树的最大加分,枚举根节点k,那么dp[i][j]=max{dp(l,k-1)*dp(k+1,r)+dp[k][k]},然后可以记忆化搜索。
#include<bits/stdc++.h>
#define FAST ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define INF 0x3f3f3f3f
typedef long long ll;
const int maxn = 1e5+5;
using namespace std;
int n;
ll a[maxn],w[maxn],root[1001][1001],rt[maxn],top;
ll dp[1001][1001];
ll solve(int l, int r)
{
if (dp[l][r]) return dp[l][r];
if (l>r) return 1;
for (int k=l; k<=r; k++)
{
if (solve(l,k-1)*solve(k+1,r)+dp[k][k]>dp[l][r])
{
dp[l][r]=solve(l,k-1)*solve(k+1,r)+dp[k][k];
root[l][r]=k;
}
}
return dp[l][r];
}
void work(int l, int r)
{
int k=root[l][r];
if (!k) return;
rt[++top]=k;
work(l,k-1);
work(k+1,r);
}
int main()
{
FAST;
cin>>n;
for (int i=1; i<=n; i++)
{
cin>>w[i];
root[i][i]=i;
dp[i][i]=w[i];
}
solve(1,n);
cout<<dp[1][n]<<endl;
work(1,n);
for (int i=1; i<=top; i++) cout<<rt[i]<<' ';
return 0;
}