洛谷 P1040 加分二叉树

      洛谷 P1040 加分二叉树

题目描述

设一个 n 个节点的二叉树tree的中序遍历为( 1,2,3,,n ),其中数字 1,2,3,,n 为节点编号。每个节点都有一个分数(均为正整数),记第 i 个节点的分数为 di,tree 及它的每个子树都有一个加分,任一棵子树 subtree (也包含 tree 本身)的加分计算方法如下:

subtree 的左子树的加分× subtree 的右子树的加分+ subtree 的根的分数。

若某个子树为空,规定其加分为 1 ,叶子的加分就是叶节点本身的分数。不考虑它的空子树。

试求一棵符合中序遍历为( 1,2,3,,n )且加分最高的二叉树 tree 。要求输出;

(1) tree 的最高加分

(2) tree 的前序遍历

输入输出格式

输入格式:

第 1 行: 1 个整数 (30) ,为节点个数。

第 2 行: n 个用空格隔开的整数,为每个节点的分数(分数 <100 )。

输出格式:

第 1 行: 1 个整数,为最高加分(Ans ≤ 4,000,000,000 )。

第 2 行: n 个用空格隔开的整数,为该树的前序遍历。

输入输出样例

输入样例#1: 复制
5
5 7 1 2 10
输出样例#1: 复制
145
3 1 2 4 5

思路:用f[i][j]表示中序遍历为 i 到 j 的一棵树的最大加分
   则:f[i][j]=max{f[i][k]*f[k+1][j]+f[k][k],k为根节点}
   用d[i][j]记录区间[i,j]的根节点, write(i,j)输出区间[i,j]这棵树
   则:write(i,j)==>wrie(i,d[i][j]-1)+d[i][j]+write(d[i][j]+1,j)

#include<cstdio>
#define M 55
using namespace std;

int n;
int f[M][M],d[M][M];

void write(int l, int r) {
    if(l > r) return;
    printf("%d ", d[l][r]);
    write(l, d[l][r]-1);
    write(d[l][r]+1, r);
}

int main() {
    scanf("%d", &n);
    for(int i = 1; i <= n; i++) {
        scanf("%d", &f[i][i]);
        d[i][i] = i, f[i+1][i] = 1;
    }
    f[1][0] = 1;
    for(int k = 2; k <= n; k++)
        for(int s = 1; s+k-1 <= n; s++)
            for(int e = s+k-1,j = s; j <= e; j++)
                if(f[s][e] < f[s][j-1] * f[j+1][e] + f[j][j]) {
                    f[s][e] = f[s][j-1] * f[j+1][e] + f[j][j];
                    d[s][e] = j;
                }
    printf("%d
", f[1][n]);
    write(1, n);
    return 0;
}
View Code

原文地址:https://www.cnblogs.com/v-vip/p/9343777.html