• 洛谷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
    ",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.

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

  • 相关阅读:
    去掉字幕文件里的时间轴信息
    Git常用命令笔记
    VMware machine里的文件
    C# Inventor二次开发—004—创建二维草图(2)
    C# Inventor二次开发—003—创建二维草图
    C# Inventor二次开发—002—启动Inventor及零部件创建和打开
    C# Inventor二次开发—001—准备工作
    UTF-8 BOM编码格式文件对SSI的影响
    滚动到顶部
    如何理解 “私有成员只有在声明它们的类和结构体中才是可访问的” ?
  • 原文地址:https://www.cnblogs.com/sy666/p/12617714.html
Copyright © 2020-2023  润新知