2003年分区联赛提高组之三 加分二叉树 dp

题目大意

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

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

 

分析

  F[I,j]表示区间|I,j|中建成加权二叉树能够取得的最大值。

  明显有转移方程f[I,j]=max{f[i,i]+f[i+1,j],f[i,j-1]+f[j,j],f[i,k-1]*f[k+1,j]+f[k,k]} 

  I+1<=k<=j-1

  同时转移的时候用G[I,j]记录路径,最后递归输出。

以上copy

一下自己写的:

1.注意题目只用输出tree的最高加分 

2.结果要用int64;

3.枚举时要先把[i,i+1]的所有区间枚举出来,再枚举[i,i+2]的所有区间枚举出来……最后枚举[i,i+n-1]的区间。具体见程序。


代码

var
  f:array[1..30,1..30] of int64;
  r:array[1..30,1..30] of longint;
  a:array[1..30] of longint;
  i,j,k,l:longint;
  n:longint;

procedure shu(ro,l:longint);
begin
  if ro<=l then
    begin
      write(r[ro,l]:3);
      shu(ro,r[ro,l]-1);
      shu(r[ro,l]+1,l);
    end;
end;

begin
  readln(n);
  for i:=1 to n do
    read(a[i]);
  fillchar(f,sizeof(f),0);
  for i:=1 to n do
    begin
      f[i,i]:=a[i];
      r[i,i]:=i;
    end;
  for l:=1 to n-1 do
    for i:=1 to n-l do
      begin
        j:=i+l;
        f[i,j]:=f[i,i]+f[i+1,j];
        r[i,j]:=i;
        if f[j,j]+f[i,j-1]>f[i,j]
          then
            begin
              f[i,j]:=f[j,j]+f[i,j-1];
              r[i,j]:=j;
            end;
        for k:=i+1 to j-1 do
          if f[i,k-1]*f[k+1,j]+f[k,k]>f[i,j]
            then
              begin
                f[i,j]:=f[i,k-1]*f[k+1,j]+f[k,k];
                r[i,j]:=k;
              end;
      end;
  writeln(f[1,n]);
end.


posted @ 2016-05-04 21:40  一个响亮的蒟蒻  阅读(109)  评论(0编辑  收藏  举报