区间DP,设f[i][j]为i到j为一棵树的最大加分。
#include<cstdio>
long long f[51][51];
int n,ans[51][51];
void dg(int q, int z){ //递归q到z的前序
if(q>z) return;
printf("%d ",ans[q][z]); //输出根
dg(q,ans[q][z]-1); //左子节点
dg(ans[q][z]+1,z); //右子节点
}
int main(){
scanf("%d",&n);
for(int i = 1; i <= n; ++i){
scanf("%lld",&f[i][i]);
ans[i][i]=i; //加分为本身
f[i][i - 1] = 1; //空子树的情况
f[i + 1][i] = 1;
}
for(int i = 2; i <= n; ++i) //枚举长度
for(int j = 1; j <= n - i + 1; ++j){ //起点
int aa = j, bb = j + i - 1; //起点,终点
for(int k = aa; k < bb; ++k) //枚举此树的根
if(f[aa][bb] < f[aa][k - 1] * f[k + 1][bb] + f[k][k]){ //如果可以更新
f[aa][bb] = f[aa][k - 1] * f[k + 1][bb] + f[k][k]; //更新
ans[aa][bb] = k; //记录根
}
}
printf("%lld\n",f[1][n]); //输出
dg(1,n); //递归输出前序
}