洛谷P1040 信息奥赛一本通1833 加分二叉树

原题链接:
洛谷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\n",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.

我可能写的不好,如果有问题,请帮忙指出,谢谢。

猜你喜欢

转载自www.cnblogs.com/sy666/p/12617714.html