加分二叉树

Posted Jozky86

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了加分二叉树相关的知识,希望对你有一定的参考价值。

加分二叉树

题意:

给你一个数的中序表达式,然后一颗子树的分数=左子树的分数*右子树的分数+根的分数
给你所有点的分数,让你构造出分值最大的树,输出前序遍历

题解:

区间dp问题
设dp[i][j]表示中序遍历是w[i~j]的所有二叉树的得分的最大值
树张什么样都可以,而我们只是想要分数最高
所以我们从小的子树开始,先决定区间长度,然后枚举区间的起点,决定区间的终点,我们求出每一小区间的最大分值,求大的区间时就用小的合并上
区间[l,r]的最大分数
k在[l,r]中,为枚举的根
dp[i][j]=max(dp[i][k-1]*dp[k+1][j]+w[k]),保留最大值的同时记录根,方便之后的前序遍历输出

代码:

#include<bits/stdc++.h>
#define debug(a,b) printf("%s = %d\\n",a,b);
typedef long long ll;
using namespace std;

inline int read(){
   int s=0,w=1;
   char ch=getchar();
   while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
   while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();//s=(s<<3)+(s<<1)+(ch^48);
   return s*w;
}
const int maxn=60;
int w[maxn];
int f[maxn][maxn];
int root[maxn][maxn];
void dfs(int l,int r){
	if(l>r)return ;
	int k=root[l][r];
	printf("%d ",k);
	dfs(l,k-1);//前 
	dfs(k+1,r);//后 
}
int main()
{
	int n;
	cin>>n;
	for(int i=1;i<=n;i++)cin>>w[i];
	for(int len=1;len<=n;len++){
		for(int i=1;i+len-1<=n;i++){
			int j=i+len-1;
			for(int k=i;k<=j;k++){
				int right,left;
				if(k==i){
					left=1;
					right=f[k+1][j];
				}
				else if(k==j)
				{
					left=f[i][k-1];
					right=1;
				}
				else 
				{
					left=f[i][k-1];
					right=f[k+1][j];
				}
				int score=left*right+w[k];
				if(score>f[i][j]){
					f[i][j]=score;
					root[i][j]=k;
				}
			}
		}
	}
	cout<<f[1][n]<<endl;
	dfs(1,n);
	return 0;
}

以上是关于加分二叉树的主要内容,如果未能解决你的问题,请参考以下文章

加分二叉树

[luoguP1040] 加分二叉树(DP)

P1040 加分二叉树

P1040 加分二叉树

洛谷P1040 加分二叉树

加分二叉树