洛谷P1040 加分二叉树

https://www.luogu.org/problemnew/show/P1040

题意:

一个 n n n个节点的二叉树,每个节点都有一个分数,每颗子树也有分数
每颗子树的分数计算方法为:
s u b t r e e 的 左 子 树 的 加 分 × s u b t r e e s u b t r e e 的 右 子 树 的 加 分 + s u b t r e e s u b t r e e 的 根 的 分 数 。 subtree的左子树的加分× subtreesubtree的右子树的加分+subtreesubtree的根的分数。 subtree×subtreesubtreesubtreesubtree
若某个子树为空,规定其加分为1,叶子的加分就是叶节点本身的分数。不考虑它的空子树
试求一棵符合中序遍历为 ( 1 , 2 , 3 , … , n ) (1,2,3,…,n) 1,2,3,,n且加分最高的二叉树 t r e e tree tree。要求输出;
(1) t r e e tree tree的最高加分
(2) t r e e tree tree的前序遍历

思路:

我们用 d p [ m ] [ i ] [ j ] dp[m][i][j] dp[m][i][j]来表示一颗以 m m m为根,子树为 i − j i-j ij的树的最大得分, s u m [ l ] [ r ] sum[l][r] sum[l][r]来代表子树节点是 i − j i-j ij的子树的最大得分
那么 d p [ m ] [ i ] [ j ] = m a x ( d p [ m ] [ i ] [ j ] , ( s u m [ i ] [ m − 1 ] ∗ s u m [ m + 1 ] [ j ] ) ∗ a [ m ] ) , s u m [ i ] [ j ] = m a x ( d p [ m ] [ i ] [ j ] , s u m [ i ] [ j ] ) dp[m][i][j]=max(dp[m][i][j],(sum[i][m-1]*sum[m+1][j]) * a[m]),sum[i][j]=max(dp[m][i][j],sum[i][j]) dp[m][i][j]=max(dp[m][i][j],(sum[i][m1]sum[m+1][j])a[m]),sum[i][j]=max(dp[m][i][j],sum[i][j])
这样状态转移就写完了, 后面就是递归输出这棵树了,每次找区间的最大值作为根节点,然后向左向右递归

void First(int l, int r) {
    int Max = 0, u = -1;
    for (int i = l; i <= r; i ++) {
        if(Max < dp[i][l][r]) {
            Max = dp[i][l][r];
            u = i;
        }
    }
    if(l == 1 && r == n) printf("%lld\n", Max);
    printf("%d ", u);
    if(u - 1 >= l) First(l, u-1);
    if(u + 1 <= r) First(u+1, r);
}

AC代码:

#include

using namespace std;

#define LL long long
const int maxn = 1e5 + 5;
const int inf = 0x3f3f3f3f;
const int Mod = 1e9 + 7;
const double eps = 1e-8;
typedef pair<int, int> psi;

void fre() {
    if(freopen("洛谷P1040.txt", "r", stdin) == NULL)
        system("touch 洛谷P1040.txt");
    freopen("洛谷P1040.txt", "r", stdin);
}

LL dp[40][40][40], a[40], sum[40][40];
int n;

void First(int l, int r) {
    int Max = 0, u = -1;
    for (int i = l; i <= r; i ++) {
        if(Max < dp[i][l][r]) {
            Max = dp[i][l][r];
            u = i;
        }
    }
    if(l == 1 && r == n) printf("%lld\n", Max);
    printf("%d ", u);
    if(u - 1 >= l) First(l, u-1);
    if(u + 1 <= r) First(u+1, r);
}

int main(int argc, char *args[]) {
    fre();
    scanf("%d", &n);
    for (int i = 1; i <= n; i ++) scanf("%lld", &a[i]);
    memset(dp, 0, sizeof(dp));
    for (int i = 0; i <= n; i ++) 
        for (int j = 0; j <= n; j ++) 
            sum[i][j] = 1;
    for (int i = 1; i <= n; i ++) dp[i][i][i] = sum[i][i] = a[i];
    for (int k = 1; k <= n-1; k ++) {
        for (int l = 1; l + k <= n; l ++) {
            for (int m = l; m <= l + k; m ++) {
                dp[m][l][l+k] = max(dp[m][l][l+k], (sum[l][m-1] * sum[m+1][l+k]) + a[m]);
                sum[l][l+k] = max(sum[l][l+k], dp[m][l][l+k]);
             }
        }
    }
    First(1, n);
    return 0;
}

你可能感兴趣的:(题解,dp)