【题解】洛谷P1040 [NOIP2003]加分二叉树

前往:我自己搭建的博客

题目

洛谷P1040加分二叉树

题解

在中序遍历的序列中,每个子区间对应一棵树,如果确定了根节点,那么该节点左侧是左子树,右侧是右子树,可以区间dp。

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=35;
int n;
int rt[maxn][maxn]; //记录区间[l,r]构成的子树的根节点 
ll f[maxn][maxn],sc[maxn]; //sc[]表示分数 
void dfs(int l,int r) //前序遍历 
{
	printf("%d ",rt[l][r]);
	if(rt[l][r]>l) dfs(l,rt[l][r]-1);
	if(rt[l][r]<r) dfs(rt[l][r]+1,r);
}
inline void dp()
{
	for(int i=1;i<=n;i++) f[i][i]=sc[i],rt[i][i]=i; //初始化 
	for(int len=2;len<=n;len++)
	{
		for(int l=1; ;l++)
		{
			int r=l+len-1; if(r>n) break;
			if(sc[l]+f[l+1][r]>f[l][r]) f[l][r]=sc[l]+f[l+1][r],rt[l][r]=l; //根节点为l的特殊情况
			if(sc[r]+f[l][r-1]>f[l][r]) f[l][r]=sc[r]+f[l][r-1],rt[l][r]=r; //根节点为r的特殊情况 
			//k为[l,r]这棵子树的根节点 
			for(int k=l+1;k<=r-1;k++) if(sc[k]+f[l][k-1]*f[k+1][r]>f[l][r]) f[l][r]=sc[k]+f[l][k-1]*f[k+1][r],rt[l][r]=k;
		}
	}
	printf("%lld\n",f[1][n]);
}

int main()
{
	scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%lld",&sc[i]);
	dp(); dfs(1,n); 
	
	return 0;
}

猜你喜欢

转载自blog.csdn.net/zjgmartin/article/details/108565110