加分二叉树
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;
}
以上是关于加分二叉树的主要内容,如果未能解决你的问题,请参考以下文章