[区间DP]【NOIP2003T3】加分二叉树 题解

本文介绍了一道洛谷题目使用区间DP算法求解的过程。通过定义状态f[i][j]表示i到j的树的最大权值,利用转移方程进行动态规划,最终实现了高效求解。

洛谷传送门在此

解题报告

一开始以为是树形DP,然后各种推理,就发现各种MLE。后来无耻的查了题解。再推一下,MD,这是个区间DP啊。

由于中序序列刚好是1…n,所以想到从里面找一个为根,然后就有左右两子树,然后又是对这两子树又分别找根。容易想到区间DP

定义 f[i][j]ij 的树的最大权值。 g[i][j] 表示最大值时的根。
转移方程如下:

f[i][j]=max(f[i][k1]f[k+1][j]+a[k])

注意初值。

复杂度:
时间: O(n3)
空间: O(n2)

#include<cstdio>
#include<cstring>
using namespace std;
int n,a[35],f[35][35],g[35][35];
inline char nc(){
    static char buf[100000],*pa=buf,*pb=buf;
    return pa==pb&&(pb=(pa=buf)+fread(buf,1,100000,stdin),pa==pb)?EOF:*pa++;
}
inline void readi(int &x){
    x=0; char ch=nc();
    while ('0'>ch||ch>'9') ch=nc();
    while ('0'<=ch&&ch<='9') {x=x*10+ch-'0'; ch=nc();}
}
void _dfs(int x,int y){
    if (x<=y){
        printf("%d ",g[x][y]);
        _dfs(x,g[x][y]-1);
        _dfs(g[x][y]+1,y);
    }
}
int main()
{
    freopen("tree.in","r",stdin);
    freopen("tree.out","w",stdout);
    readi(n);
    for (int i=0;i<=n;i++)
        for (int j=0;j<=n;j++) f[i][j]=1;
    for (int i=1;i<=n;i++){
        readi(a[i]); g[i][i]=i; f[i][i]=a[i];
    }
    for (int L=2;L<=n;L++)
        for (int i=1,j;i<=n-L+1;i++){
            j=i+L-1;
            for (int k=i;k<=j;k++)
                if (f[i][j]<f[i][k-1]*f[k+1][j]+a[k]){
                    g[i][j]=k;
                    f[i][j]=f[i][k-1]*f[k+1][j]+a[k];
                }
        }
    printf("%d\n",f[1][n]); _dfs(1,n);
    return 0;
}
设一个 n n 个节点的二叉树 t r e e tree 的中序遍历为 ( 1 , 2 , 3 , … , n ) (1,2,3,…,n) ,其中数字 1 , 2 , 3 , … , n 1,2,3,…,n 为节点编号。每个节点都有一个分数(均为正整数),记第 i i 个节点的分数为 d i , t r e e d i ​ ,tree 及它的每个子树都有一个加分,任一棵子树 s u b t r e e subtree (也包含 t r e e tree 本身)的加分计算方法如下: s u b t r e e 的左子树的加分 × s u b t r e e 的右子树的加分+ s u b t r e e 的根的分数 subtree的左子树的加分×subtree的右子树的加分+subtree的根的分数 若某个子树为空,规定其加分为 1 1 ,叶子的加分就是叶节点本身的分数。不考虑它的空子树。 试求一棵符合中序遍历为 ( 1 , 2 , 3 , … , n ) (1,2,3,…,n) 且加分最高的二叉树 t r e e tree 。要求输出; ( 1 ) t r e e 的最高加分 (1)tree的最高加分 ( 2 ) t r e e 的前序遍历 (2)tree的前序遍历。 【输入格式】 第 1 1 行:一个整数 n n,为节点个数。 第 2 2 行: n n 个用空格隔开的整数,为每个节点的分数(分数 < 100 <100 )。 【输出格式】 第 1 1 行:一个整数,为最高加分(结果不会超过 4 , 000 , 000 , 000 4,000,000,000 )。 第 2 2 行: n n 个用空格隔开的整数,为该树的前序遍历。 【样例输入1】 5 5 7 1 2 10 【样例输出1】 145 3 1 2 4 5 【样例1解释】 无 【数据范围及约定】 1 ≤ n < 30 1≤n<30
最新发布
10-29
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值