luogu1040 加分二叉树

Posted headboy2002

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了luogu1040 加分二叉树相关的知识,希望对你有一定的参考价值。

题目大意

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

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

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

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

1tree的最高加分

2tree的前序遍历

题解

  本题最容易忽略的性质便是二叉树中的每一个子树的中序遍历都是一段连续的区间。所以对于一段区间,根据选区间中哪个点作为根来分类动规即可。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstdarg>
using namespace std;

void _printf(char *format, ...)
{
#ifdef _DEBUG
    va_list(args);
    va_start(args, format);
    vprintf(format, args);
    va_end(args);
#endif
}
//-------------------------------------------------------------------------
const int MAX_NODE = 35;
long long F[MAX_NODE][MAX_NODE];
int RootId[MAX_NODE][MAX_NODE], Val[MAX_NODE];
int TotNode;

void DP()
{
    for (int i = 1; i <= TotNode; i++)
    F[i][i - 1] = F[i][i + 1] = 1;
    for (int i = 1; i <= TotNode; i++)
    {
    F[i][i] = Val[i];
    RootId[i][i] = i;
    }
    for (int len = 2; len <= TotNode; len++)
    for (int i = 1; i <= TotNode - len + 1; i++)
    {
        int j = i + len - 1;
        for (int k = i; k <= j; k++)
        {
        if (F[i][k - 1] * F[k + 1][j] + Val[k] > F[i][j])
        {
            F[i][j] = F[i][k - 1] * F[k + 1][j] + Val[k];
            RootId[i][j] = k;
        }
        }
    }
}

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

int main()
{
#ifdef _DEBUG
    freopen("c:\noi\source\input.txt", "r", stdin);
#endif
    scanf("%d", &TotNode);
    for (int i = 1; i <= TotNode; i++)
    scanf("%d", Val + i);
    DP();
    printf("%lld
", F[1][TotNode]);
    Print(1, TotNode);
    return 0;
}

  

以上是关于luogu1040 加分二叉树的主要内容,如果未能解决你的问题,请参考以下文章

树形dp入门-加分二叉树(luogu1040)

Luogu1040 加分二叉树

P1040 加分二叉树

洛谷1040 加分二叉树 区间dp

P1040 加分二叉树

加分二叉树