加分二叉树
ssl 1033
luogu 1040
题目大意:
有一棵中序遍历为1,2,3…n的二叉树(当然二叉树的样子没有固定),现在给出每个节点的分数,一个节点的加数=两个子节点的加数相乘+当前节点的分数(空的子节点加数为1,叶子节点加数为它的分数),现在要你求最大的加数
输入样例
5
5 7 1 2 10
输出样例
145
3 1 2 4 5
数据范围
n<30n<30n<30
Ans⩽4,000,000,000Ans \leqslant 4,000,000,000Ans⩽4,000,000,000
解题思路:
设f[i][j]f[i][j]f[i][j]为中序遍历为i~j的子树的最大加数,然后每次枚举中间点去划分树,然后DP即可
代码:
#include<cstdio>
#define max(a,b) (a)>(b)?(a):(b)
using namespace std;
long long n,a[50],f[50][50],s[50][50];
void dg(long long l,long long r)//递归输出前序遍历
{if (l>r) return;printf("%lld ",s[l][r]);dg(l,s[l][r]-1);dg(s[l][r]+1,r);
}
int main()
{scanf("%lld",&n);for(int i=1;i<=n;++i){f[i][i-1]=1;//处理空子树的情况f[i+1][i]=1;scanf("%lld",&a[i]);f[i][i]=a[i];s[i][i]=i; }for(int i=n-1;i>0;--i)//倒着枚举可以先做小的再做大的for(int j=i+1;j<=n;++j)//枚举范围for(int k=i;k<=j;++k)//中间点if (f[i][k-1]*f[k+1][j]+a[k]>f[i][j]){f[i][j]=f[i][k-1]*f[k+1][j]+a[k];//DPs[i][j]=k;}printf("%lld\n",f[1][n]);dg(1,n);
}