1.给定中序遍历1,2,3....n,作用:越小的号码放在“越左子树”,对树的形状并没有什么限制。
2.给定计算方式为左子树分数*右子树分数+根节点分数,所以对一个已知确定的树只需要摆定他的根就可以确定其得分 对此可以递归子树加枚举处理,而如何确定一个数(根可不定)由于中序遍历给定,所以对于任一个区间[i,j]可以达到需要,对于每个区间递归枚举根即可(这里采用记忆化搜索)
#include<iostream>
#include<cstring>
#include<vector>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long ll;
const int inf=0x7f7f7f7f;
const int nn=1e5+50;
const double eps=1e-6;
inline int read() {
int x=0,f=1;
char c=getchar();
while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
return x*f;
}
inline void write(int x) {
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10+'0');
}
int dp[35][35],root[35][35];
inline int solve(int l,int r)
{
if(l>r)
return 1;
int pos;
if(dp[l][r]==-1)
{
for(int k=l;k<=r;++k)
{
if(dp[l][r]<solve(l,k-1)*solve(k+1,r)+dp[k][k])
{
dp[l][r]=solve(l,k-1)*solve(k+1,r)+dp[k][k];
pos=k;
}
}
root[l][r]=pos;
}
return dp[l][r];
}
int f=0;
inline void preorder(int l,int r)
{
if(l>r)
return ;
if(f==0)
f=1;
else cout<<' ';
cout<<root[l][r];
preorder(l,root[l][r]-1);
preorder(root[l][r]+1,r);
}
int main ()
{
int n;
n=read();
for(int i=1;i<=n;++i)
{
for(int j=1;j<=n;++j)
dp[i][j]=-1;
}
for(int i=1;i<=n;++i)
{
dp[i][i]=read();
root[i][i]=i;
}
solve(1,n);
cout<<dp[1][n]<<endl;
preorder(1,n);
return 0;
}