题目描述
设一个nn个节点的二叉树tree的中序遍历为(1,2,3,…,n1,2,3,…,n),其中数字1,2,3,…,n1,2,3,…,n为节点编号。每个节点都有一个分数(均为正整数),记第ii个节点的分数为di,treedi,tree及它的每个子树都有一个加分,任一棵子树subtreesubtree(也包含treetree本身)的加分计算方法如下:
subtreesubtree的左子树的加分× subtreesubtree的右子树的加分+subtreesubtree的根的分数。
若某个子树为空,规定其加分为11,叶子的加分就是叶节点本身的分数。不考虑它的空子树。
试求一棵符合中序遍历为(1,2,3,…,n1,2,3,…,n)且加分最高的二叉树treetree。要求输出;
(1)treetree的最高加分
(2)treetree的前序遍历
输入输出格式
输入格式:
第1行:1个整数n(n<30),为节点个数。
第2行:n个用空格隔开的整数,为每个节点的分数(分数<100<100)。
输出格式:
第1行:1个整数,为最高加分(Ans \le 4,000,000,000≤4,000,000,000)。
第2行:n个用空格隔开的整数,为该树的前序遍历。
输入输出样例
输入样例#1
5 5 7 1 2 10
输出样例#1
145 3 1 2 4 5
思路
树形dp啊..不过区间dp或者dfs暴力都可以。
这题是不需要剪枝的,如果数据再大点估计只能用dp了。
#include <stdio.h>
#include <iostream>
#include <algorithm>
using namespace std;
int dp[51][51],n,s,tree[51][51];
int dfs(int l,int r)
{
if(l>r)
{
return 1;
}
register int i,now;
if(dp[l][r]==-1)
{
for(i=l;i<=r;i++)
{
now=dfs(l,i-1)*dfs(i+1,r)+dp[i][i];//计算父亲节点的分数
if(now>dp[l][r])//如果当前找到最大分数
{
dp[l][r]=now;//记录最大分数
tree[l][r]=i;//记录根节点
}
}
}
return dp[l][r];//返回目前最优的分数
}
void pre_dfs(int l,int r)
{
if(l>r) return;
cout<<tree[l][r]<<' ';
pre_dfs(l,tree[l][r]-1);//左子树
pre_dfs(tree[l][r]+1,r);//右子树
return;//根-左-右
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
register int i,j,k;
cin>>n;
for(i=1;i<=n;i++)
{
for(j=i;j<=n;j++)
{
dp[i][j]=-1;//初始化
}
cin>>dp[i][i];
tree[i][i]=i;//树根节点
}
cout<<dfs(1,n)<<endl;//♂
pre_dfs(1,n);
cout<<endl;
return 0;
}
因为这题还是区间dp的好题,所以标签还会打上区间dp。