洛谷P1040 加分二叉树【记忆化搜索】

题目链接:https://www.luogu.org/problemnew/show/P1040

题意:

某一个二叉树的中序遍历是1~n,每个节点有一个分数(正整数)。

二叉树的分数是左子树分数乘右子树分数加根节点分数,如果子树为空分数是1.

现在想知道这个二叉树最大的分数是多少,并且输出前序遍历结果。

思路:

$f[i][j]$表示$i$~$j$号节点组成的子树的最大分数,为了最后能输出前序遍历结果用$root[i][j]$表示$i~j$号节点组成的子树的根

枚举根节点,记忆化搜索。

//#include<bits/stdc++>
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<stdlib.h>
#include<queue> 
#include<map>
#include<stack>
#include<set>

#define LL long long
#define ull unsigned long long
#define inf 0x3f3f3f3f 

using namespace std;
int n;
int sco[35];
LL f[35][35];
int root[35][35];
bool flag = false;

LL dfs(int i, int j)
{
    if(f[i][j]) return f[i][j];
    if(j < i){
        //root[i][j] = i;
        return 1;
    }
    
    for(int k = i; k <= j; k++){
        LL t = dfs(i, k - 1) * dfs(k + 1, j) + sco[k];
        if(f[i][j] < t){
            root[i][j] = k;    
            f[i][j] = t;
        }
    }
    return f[i][j];
}

void print(int i, int j){
    if(i > j){
        return;
    }
    if(flag)printf(" ");
    else{
        flag = true;
    }
    printf("%d", root[i][j]);
    print(i, root[i][j] - 1);
    //printf(" %d", root[i][j]);
    print(root[i][j] + 1, j);
    return;
}

int main()
{
    scanf("%d", &n);
    for(int i = 1; i <= n; i++){
        scanf("%d", &sco[i]);
        f[i][i] = sco[i];
        root[i][i] = i;
    }
    LL ans = dfs(1, n);
    cout<<ans<<endl;
    print(1, n);
    return 0;    
} 

猜你喜欢

转载自www.cnblogs.com/wyboooo/p/10348286.html