加分二叉树

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);
}
posted @ 2019-11-11 21:12  fbz  阅读(124)  评论(0编辑  收藏  举报