[NOIP2003]加分二叉树

题目描述

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

  subtree的左子树的加分× subtree的右子树的加分+subtree的根的分数。
  若某个子树为空,规定其加分为1,叶子的加分就是叶节点本身的分数。不考虑它的空子树。
  试求一棵符合中序遍历为(1,2,3,…,n)且加分最高的二叉树tree。要求输出;
  (1)tree的最高加分
  (2)tree的前序遍历

输入输出格式

输入格式:

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

输出格式:

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

输入输出样例

输入样例#1:

5
5 7 1 2 10

输出样例#1:

145
3 1 2 4 5

思路

  f[i,j]是中序遍历为从i到j时的最大加分。

  枚举所有的可能中序遍历结果,枚举当前中序遍历中所有可能的根节点。

  转移方程:f[i,j]:=max(f[i,k-1]*f[k+1,j]+a[k])

       (i<k<j)

  初始化:f[i,j]=1;f[i,i]:=a[i];

var a:array[1..100] of longint;  
    root,f:array[0..100,0..100] of longint;  
    n:longint;  
  
procedure init;  
var i:longint;  
begin  
    readln(n);  
    for i:=1 to n do read(a[i]);  
end;  
  
procedure dp();  
var i,j,p,k:longint;  
begin  
    for i:=0 to n do  
        for j:=0 to n do  
            f[i,j]:=1;  
    for i:=1 to n do  
        begin  
            f[i,i]:=a[i];  
            root[i,i]:=i;  
        end;  
    for p:=1 to n-1 do  
        for i:=1 to n-p do  
            begin  
                j:=i+p;  
                f[i,j]:=0;  
                for k:=i to j do  
                    if f[i,j]<f[i,k-1]*f[k+1,j]+a[k] then  
                        begin  
                            f[i,j]:=f[i,k-1]*f[k+1,j]+a[k];  
                            root[i,j]:=k;  
                        end;  
            end;  
end;  
  
procedure mid(i,j:longint);  
begin  
    if i<=j then  
        begin  
            write(root[i,j],' ');  
            mid(i,root[i,j]-1);  
            mid(root[i,j]+1,j);  
        end;  
end;  
  
begin  
    init;  
    dp();  
    writeln(f[1,n]);  
    mid(1,n);  
end.  
View Code

 

posted on 2015-10-24 11:13  川汉唐  阅读(381)  评论(0编辑  收藏  举报

导航