加分二叉树[NOIP 2003提高组][Codevs 1090]

来源:互联网 发布:淘宝怎么改名字啊 编辑:程序博客网 时间:2024/05/09 20:55

题目描述 Description

设一个 n 个节点的二叉树 tree 的中序遍历为 (1,2,3,,n) ,其中数字 1,2,3,,n 为节点编号。每个节点都有一个分数(均为正整数),记第j个节点的分数为 ditree 及它的每个子树都有一个加分,任一棵子树 subtree (也包含 tree 本身)的加分计算方法如下:

subtree 的左子树的加分× subtree 的右子树的加分+subtree 的根的分数

若某个子树为主,规定其加分为 1 ,叶子的加分就是叶节点本身的分数。不考虑它的空子树。

试求一棵符合中序遍历为 (1,2,3,,n) 且加分最高的二叉树 tree 。要求输出;
(1)  tree 的最高加分
(2)  tree 的前序遍历

现在,请你帮助你的好朋友XZ设计一个程序,求得正确的答案。


输入描述 Input Description

1 行:一个整数 n(n30),为节点个数。
2 行: n 个用空格隔开的整数,为每个节点的分数 ( 分数 100)


输出描述 Output Description

1 行:一个整数,为最高加分(结果不会超过 4000000000)。
2 行: n 个用空格隔开的整数,为该树的前序遍历。


样例输入 Sample Input

5
5 7 1 2 10


样例输出 Sample Output

145
3 1 2 4 5


数据范围及提示 Data Size & Hint

n(n30)
分数 100


分析 I Think

因为设 tree 的根节点的编号为 k ,则左子树的编号为 1~(k1) ,右子树的编号为 (k+1)~n
fi,j 表示编号为 i~j ,中序遍历为 i~j 的树的最大加分,其中其根节点为 ri,j,则 fi,j=max{fi,k1,+ak+fk+1,j},其中 k 为枚举的根节点


代码 Code

#include <cstdio>#include <cstring>#include <algorithm>using namespace std;int f[40][40];int r[40][40];int a[40];int n;void display(int,int);int main(){    scanf("%d",&n);    for(int i=1;i<=n;++i)        scanf("%d",&a[i]);    for(int i=1;i<=n;++i){        f[i][i] = a[i];        r[i][i] = i;        f[i][i+1] = a[i]+a[i+1];        r[i][i+1] = i;    }    for(int i=n-2;i>=1;--i)        for(int j=i+2;j<=n;++j){            f[i][j] = a[i]+f[i+1][j];            r[i][j] = i;            if(a[j]+f[i][j-1] > f[i][j]){                f[i][j] = a[j]+f[i][j-1];                r[i][j] = j;            }            for(int k=i+1;k<j;++k)                if(a[k]+f[i][k-1]*f[k+1][j] > f[i][j]){                    f[i][j] = a[k]+f[i][k-1]*f[k+1][j];                    r[i][j] = k;                }        }    printf("%d\n",f[1][n]);    display(1,n);    return 0;}void display(int L,int R){    printf("%d ",r[L][R]);    if(L < r[L][R])        display(L,r[L][R]-1);    if(R > r[L][R])        display(r[L][R]+1,R);}
0 0
原创粉丝点击