SSL 1033 加分二叉树 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的前序遍历 


分析:很裸的dp。f[i,j]表示节点i到节点j的最高加分是多少。

很显然f[i,j]=max(d[i]+f[i+1,j],d[j]+f[i,j-1],f[i,k-1]*f[k+1,j]+d[k]){i+1<=k<=j-1}


代码:

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

procedure print(x,y:longint);
begin
  if x>y then exit;
  write(g[x,y]:3);
  print(x,g[x,y]-1);
  print(g[x,y]+1,y);
end;

begin
  readln(n);
  for i:=1 to n do
    read(a[i]);
  for i:=1 to n do
  begin
    f[i,i]:=a[i];
    g[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];
      g[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];
        g[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];
          g[i,j]:=k;
        end;
    end;
  writeln(f[1,n]);
  print(1,n);
end.


你可能感兴趣的:(SSL 1033 加分二叉树 dp)