nowcoder-NC16681--加分二叉树(区间DP)

题目戳我

题意:

给一颗有 n个结点的树的中序遍历,让你算出一种构造方法使得该树的分数最大,且输出方案,分数的计算如下:
① 叶子结点的分数就是它本身的权值;
② 非叶子结点,若该结点有两颗子树,则为两颗子树的分数相乘加上该结点的权值,若该结点只有一颗子树,则为这颗子树的分数加上该结点的权值
最后整颗树的分数就是根节点的分数

思路:

可以知道若中序遍历是这样的 a1,a2,a3,a4,…,an,若这颗是以a3为根节点的树那么,a1 ~ a2就是它的左子树,a4 ~ an就是它的右子树。那么a3就是区间[1,n]的根或者说合并点,然后得到的分数就是a1 ~ a2 合并的分数加上a4 ~ an合并的分数,和合并石子的区间DP问题一样,但是要记录方案就是记录每一个合并点是哪个,因为输出前序遍历,只需要递归地输出就可以了先输出(1,n)的合并点k,然后输出(1,k-1)的合并点…

#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 35;
int n,w[N],f[N][N],g[N][N];
void dfs(int l,int r){
    if(l > r) return;
    int root = g[l][r];
    printf("%d ",root);
    dfs(l,root-1);
    dfs(root+1,r);
}
int main(){
    scanf("%d",&n);
    for(int i = 1;i <= n;i++) scanf("%d",w+i);
    for(int len = 1;len <= n;len++){
        for(int i = 1;i+len-1 <= n;i++){
            int j = i+len-1;
            if(len == 1){
                f[i][j] = w[i];
                g[i][j] = i;
            }else{
                //枚举以谁为根节点
                for(int k = i;k <= i+len-1;k++){
                    int left = (k==i?1:f[i][k-1]);
                    int right = (k==j?1:f[k+1][j]);
                    int score = left*right + w[k];
                    if(f[i][j] < score){
                        f[i][j] = score;
                        g[i][j] = k;
                    }
                }
            }
        }
    }
    printf("%d\n",f[1][n]);
    dfs(1,n);
    puts("");
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值