[题解](树形dp/记忆化搜索)luogu_P1040_加分二叉树

时间:2023-03-08 16:21:26

树形dp/记忆化搜索

首先可以看出树形dp,因为第一个问题并不需要知道子树的样子,

然而第二个输出前序遍历,必须知道每个子树的根节点,需要在树形dp过程中记录,递归输出

那么如何求最大加分树——根据中序的特征,想到以枚举根结点为起点
那么轻易得出如果根结点的编号为x,那么左子树的结点有1~x-1,右子树 结点有x+1~n
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int n,d[];
int f[][];
int rt[][];
int dfs(int l,int r){
if(l>r)return ;//无儿子
if(l==r){
rt[l][r]=l;return d[l];
}
if(f[l][r])return f[l][r];
int ans=,root;
for(int i=l;i<=r;i++){//枚举根
int tmp=dfs(l,i-)*dfs(i+,r)+d[i];
if(tmp>ans){
ans=tmp;
root=i;//根
}
}
rt[l][r]=root;
f[l][r]=ans;
return ans;
}
void print(int l,int r){
if(l>r)return;
printf("%d ",rt[l][r]);
print(l,rt[l][r]-);
print(rt[l][r]+,r);
}
int main(){
scanf("%d",&n);
for(int i=;i<=n;i++)scanf("%d",&d[i]);
printf("%d\n",dfs(,n));
print(,n);
}