原题链接:
洛谷https://www.luogu.org/problem/P1040
信息奥赛一本通http://ybt.ssoier.cn:8088/problem_show.php?pid=1833
【题目描述】
设一个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
这是一道搜索的题目,令k[i]表示第i个节点的分数,a[l][r].f表示从第l个节点到第r的节点所能表示出的分数这搞得树,a[l][r].g表示该树的树根是什么。
那么a[l][r].f=max(a[l][i-1].f*a[i+1][r].f+k[i]),a[l][r].g就是a[l][r].f取最大值时i的值;
输出的时候可以先输出a[l][r].g在左右递归输出a[l][a[l][r].g-1],a[a[l][r].g+1][l]。
代码:
c:
#include<stdio.h> struct node{ long long f;//a[l][r].f表示从l到r的最大分 int g;//a[l][r].g表示f最大时的根节点 }a[31][31]; int k[31],n; struct node ss(int l,int r){//搜索 if(a[l][r].f!=-1)return a[l][r]; struct node maxx,p,p1; maxx=ss(l,r-1);maxx.f+=k[r];//处理右子树为空的情况 p=ss(l+1,r);p.f+=k[l];//处理左子树为空的情况 if(p.f>maxx.f)maxx=p; for(int i=l+1;i<r;i++){//求最大值 p=ss(l,i-1);p1=ss(i+1,r); if(p.f*p1.f+k[i]>maxx.f)maxx=(struct node){p.f*p1.f+k[i],i}; } return(a[l][r]=maxx);//记忆化 } void sc(int l,int r){//输出 printf("%d ",a[l][r].g);//输出根节点 if(a[l][r].g>l)sc(l,a[l][r].g-1); if(a[l][r].g<r)sc(a[l][r].g+1,r);//递归左右节点 return; } int main(){ scanf("%d",&n); for(int i=1;i<=n;i++)scanf("%d",&k[i]); for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)a[i][j]=(struct node){-1,-1}; //初始化 for(int i=1;i<=n;i++)a[i][i]=(struct node){k[i],i};//处理l=r的情况 struct node anss=ss(1,n); printf("%lld ",anss.f); sc(1,n); return 0; }
pascal:
type node=record f:int64;//a[l][r].f表示从l到r的最大分 g:longint;//a[l][r].g表示f最大时的根节点 end; var a:array[1..30,1..30]of node; k:array[1..30]of longint; n:longint; procedure ss(l,r:longint);//搜索 var i:longint; maxx:longint; m:int64; begin if a[l,r].f<>-1 then exit(); ss(l+1,r);//处理左子树为空的情况 ss(l,r-1);//处理右子树为空的情况 if a[l,r-1].f+k[r]>a[l+1,r].f+k[l] then begin maxx:=r;m:=a[l,r-1].f+k[r];end else begin maxx:=l;m:=a[l+1,r].f+k[l];end; for i:=l+1 to r-1 do begin//求最大值 ss(l,i-1);ss(i+1,r); if a[l,i-1].f*a[i+1,r].f+k[i]>m then begin maxx:=i; m:=a[l,i-1].f*a[i+1,r].f+k[i]; end; end; a[l,r].f:=m; a[l,r].g:=maxx;//记忆化 exit(); end; procedure sc(l,r:longint);//输出 begin write(a[l,r].g);//输出根节点 write(' '); if a[l,r].g>l then sc(l,a[l,r].g-1); if a[l,r].g<r then sc(a[l,r].g+1,r);//递归左右节点 exit(); end; var i,j:longint; begin readln(n); for i:=1 to n do read(k[i]);readln(); for i:=1 to n do for j:=1 to n do a[i,j].f:=-1;//初始化 for i:=1 to n do begin a[i,i].f:=k[i];a[i,i].g:=i;end;//处理l=r的情况 ss(1,n); writeln(a[1,n].f); sc(1,n); exit(); end.
我可能写的不好,如果有问题,请帮忙指出,谢谢。