[luogu] P1040 加分二叉树

题目详情
题目分析:解法是记忆化搜索。
val[i][j]存的是i到j区间内的最高加分。
tree[33] 据题意可得,tree数组存的是树的中序遍历顺序。
root[i][j]存的是tree数组从i到j的最优根,即以此为根保证此子树最高加分。
通过中序遍历性质可知:若x为根节点,1~x - 1为左子树,x + 1 ~n为右子树。

代码:

#include <cstdio>
unsigned int n, val[33][33], tree[33], root[33][33];//数据范围小于4,000,000,000
unsigned int dfs(int l, int r){
    if (r < l) return 1;//没有子树,返回一
    if (l == r){//刚好是叶子
        root[l][r] = l;
        return tree[l];
    }
    if (val[l][r]) return val[l][r];//记忆化,若搜索过直接返回
    for (int i = l; i <= r; i++){
        unsigned int sum = dfs(l, i - 1) * dfs(i + 1, r) + tree[i];//求加分
        if (sum > val[l][r]) val[l][r] = sum, root[l][r] = i;//更新,使val[i][j]保持最高加分。
    }
    return val[l][r];//返回最高加分。
}
void preOrder(int l, int r){//输出前序遍历。
    if (l > r)//没有子树直接返回。
        return;
    printf("%d ", root[l][r]);
    preOrder(l, root[l][r] - 1);
    preOrder(root[l][r] + 1, r);
}
int main(){
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) scanf("%d", &tree[i]);//按顺序输入中序遍历。
    printf("%u\n", dfs(1, n));
    preOrder(1, n);
}
发布了18 篇原创文章 · 获赞 0 · 访问量 396

猜你喜欢

转载自blog.csdn.net/weixin_45646006/article/details/105170902