加分二叉树
https://loj.ac/problem/10158
题目描述
设一个点的中序遍历为\(1,2,3,...,n\),二叉树的分数为左子树分数\(\times\)右子树分数+根的分数。求最大分数及对应的前序遍历。
思路
我们考虑用\(f[i][j]\)表示\(i\sim j\)的这一段的最大分数,我们只要暴力枚举以\(k\in [i,j]\)为根的点的最大分数,并记录一下这一段以那个点为根即可。最后递归求一下前序遍历即可。
代码
#include<bits/stdc++.h>
using namespace std;
int read()
{
int res=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){res=(res<<3)+(res<<1)+(ch^48);ch=getchar();}
return res*w;
}
void write(int x)
{
if(x<0){putchar('-');x=-x;}
if(x>9)write(x/10);
putchar(x%10+'0');
}
void writeln(int x)
{
write(x);
putchar('\n');
}
int f[40][40],a[40],p[40][40];
void output(int l,int r)
{
int k=p[l][r];
write(k);putchar(' ');
if(k-1>=l)output(l,k-1);
if(k+1<=r)output(k+1,r);
}
int main()
{
int n=read();
for(int i=1;i<=n;i++)
a[i]=read();
for(int i=1;i<=n+1;i++)
f[i][i-1]=1;
for(int i=1;i<=n;i++)
f[i][i]=a[i],p[i][i]=i;
for(int len=2;len<=n;len++)
for(int l=1;l<=n-len+1;l++)
{
int r=l+len-1;
for(int k=l;k<=r;k++)
if(f[l][r]<f[l][k-1]*f[k+1][r]+a[k])
{
f[l][r]=f[l][k-1]*f[k+1][r]+a[k];
p[l][r]=k;
}
}
writeln(f[1][n]);
output(1,n);
}