首页 > 代码库 > NOIP2003TG 加分二叉树 区间DP
NOIP2003TG 加分二叉树 区间DP
加分二叉树 (binary)
【问题描述】
设一个 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 的前序遍历
【输入格式】
第 1 行:一个整数 n ( n < 30 ),为节点个数。
第 2 行: n 个用空格隔开的整数,为每个节点的分数(分数< 100 )。
【输出格式】
第 1 行:一个整数,为最高加分(结果不会超过 4,000,000,000 )。
第 2 行: n 个用空格隔开的整数,为该树的前序遍历。
【输入样例】
5
5 7 1 2 10
【输出样例】
145
3 1 2 4 5
思路
{
因为是中序遍历,所以如果i为根节点,那么1..i-1是左子树,i+1..j为右子树
于是你就发现了每次的决策
所以这是一道区间DP。。。
用f[i,j]为i..j构成的树所能得到的最大分值
那么可以得到DP方程:
f[i,j]:=fen[i] | i=j
f[i,j]:=max(f[i,j],f[i,k-1]*f[k+1,j]+fen[k]) | i<=k<=j
//注意子树相乘时如果子树为0就当1 处理,
//if f[i,k-1]=0 then f[i,k-1]:=1;
//if f[k+1,j]=0 then f[k+1,j]:=1;
//例如:
// 如果左子树为0 , 那么左子树当为1 ,因为1*右子树=右子树
}
代码
1 program no; 2 const 3 inf=‘binary.in‘; 4 outf=‘binary.out‘; 5 var 6 i,j,k,n,t1,t2:longint; 7 f,root:array[0..100,0..100] of int64; 8 fen:array[0..100] of longint; 9 10 procedure outfirst(s,e:longint);11 begin12 if s>e then exit;13 write(root[s,e],‘ ‘);14 outfirst(s,root[s,e]-1);15 outfirst(root[s,e]+1,e);16 end;17 18 begin19 assign(input,inf);20 assign(output,outf);21 reset(input);22 rewrite(output);23 24 readln(n);25 for i:= 1 to n do26 begin27 read(fen[i]);28 f[i,i]:=fen[i];29 root[i,i]:=i;30 end;31 32 for i:=n downto 1 do33 for j:= i+1 to n do34 for k:= i to j do35 begin36 if f[i,k-1]=0 then f[i,k-1]:=1;37 if f[k+1,j]=0 then f[k+1,j]:=1;38 t1:=f[i,k-1];39 t2:=f[k+1,j];40 if f[i,j]<t1*t2+fen[k] then41 begin42 f[i,j]:=t1*t2+fen[k];43 root[i,j]:=k;44 end;45 end;46 47 writeln(f[1,n]);48 outfirst(1,n);49 50 close(input);51 close(output);52 end.
NOIP2003TG 加分二叉树 区间DP