加分二叉树

具体解释在代码内

区间动归,F[i,j]表示i到j这个区间的最优解,g[i,j]表示这个区间最优解内的情况下的根结点

f[i,j]:=max(f[i,k-1]*f[k+1,j]+a[k]),k为区间内枚举

k可以恰好为i或j这两个端点,此时需要特殊处理,即价值为f[i,j]:=1*f[i+1,j]+a[i]   (k取i时)

 1 {加分二叉树}
2 program sky;
3 var {int64}
4 i,j,k,n,tp:longint;
5 g:array[0..31,0..31] of int64;{注意f数组要开int64}
6 f:array[0..31,0..31] of int64;
7 a:array[0..31] of int64;
8 function max(qq,ww:int64):int64;{function要开……}
9 begin
10 if qq>ww then exit(qq); exit(ww);
11 end;
12 procedure print(l,r:longint);{这么个遍历的小程序都纠结了一会}
13 begin
14 write(g[l,r],' ');
15 if l<=g[l,r]-1 then print(l,g[l,r]-1);{if怎么加的问题……}
16 if r>=g[l,r]+1 then print(g[l,r]+1,r);
17 end;
18 begin
19 assign(input,'tree.in'); reset(input);
20 assign(output,'tree.out'); rewrite(output);
21 readln(n);
22 for i:=1 to n do read(a[i]);
23 for i:=1 to n do f[i,i]:=a[i];{f[i,i]g和[i,i]都要赋初值,因为走不到,而靠程序自己走到的话会出错,更新将是对一个f[i,i]以i为根f[i,i]:=1*1+a[i],因为左右子树都是0,即f[i,i-1]和f[i+1,i]}
24 for i:=1 to n do g[i,i]:=i;
25 for i:=n downto 1 do{downto,正向循环的话一开始就把F[1,n]跟新了,此时后面的状态还没出完全,不可能是对的}
26 for j:=i to n do
27 if i<>j then{即上述情况}
28 for k:=i to j do
29 begin
30 tp:=f[i,j];
31 f[i,j]:=max(max(1,f[i,k-1])*max(1,f[k+1,j])+a[k],f[i,j]);{当只有一个儿子的时候}
32 if f[i,j]>tp then g[i,j]:=k;{记录方案}
33 end;
34 writeln(f[1,n]);
35 print(1,n);
36 close(input); close(output);
37 end.

skysun原创,转载请注明出处 http://www.cnblogs.com/skysun

原文地址:https://www.cnblogs.com/skysun/p/2404701.html