加分二叉树

https://loj.ac/problem/10158

题目描述

  设一个点的中序遍历为(1,2,3,...,n),二叉树的分数为左子树分数( imes)右子树分数+根的分数。求最大分数及对应的前序遍历。

思路

  我们考虑用(f[i][j])表示(isim j)的这一段的最大分数,我们只要暴力枚举以(kin [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('
');
}

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);
}
原文地址:https://www.cnblogs.com/fangbozhen/p/11838511.html