zoukankan      html  css  js  c++  java
  • 加分二叉树(记忆化搜索+树)

    题意:有一棵n个节点的二叉树,已知每个节点的权值,求其满足中序遍历为1,2,3...n的条件下加分最高的二叉树,输出该二叉树的加分最大值和前序遍历.

    计算加分方法如下:

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

    若某个子树为空,规定其加分为1.

    叶子的加分就是叶节点本身的分数.

    分析:加分最大值直接记忆化搜索,设f[i][j]表示[i,j]这段序列(节点)可获得的最大加分.

    输出前序遍历:因为中序遍历有个特点,在中序遍历的序列上,某个点左边的序列一定在这个点的左子树上,右边的序列一定在这个点的右子树上.设root[i,j]表示[i,j]这段序列的根,递归输出先序遍历即可.

    #include<bits/stdc++.h>
    using namespace std;
    int n,val[51],f[51][51],root[51][51];
    int dfs(int l,int r){
        if(f[l][r])return f[l][r];
        if(l==r)return val[l];//叶节点的加分是本身
        if(r<l)return 1;
        for(int i=l;i<=r;i++){
            int cnt=dfs(l,i-1)*dfs(i+1,r)+f[i][i];
     //枚举i作为[l,r]这段序列的根,然后计算得分
            if(cnt>f[l][r]){
                f[l][r]=cnt;//更新最大值
    	    	root[l][r]=i;//同时更新根节点编号
            }
        }
        return f[l][r];//记忆化
    }
    void print(int l,int r){//递归输出前序遍历
        if(r<l)return;
        if(l==r){printf("%d ",l);return;}
        printf("%d ",root[l][r]);//根
        print(l,root[l][r]-1);//根的左边
        print(root[l][r]+1,r);//根的右边
    }
    int main(){
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
    		scanf("%d",&val[i]);
    		f[i][i]=val[i];//叶结点的加分等于本身
        }
        printf("%d
    ",dfs(1,n));
        print(1,n);
        return 0;
    } 
    
    
  • 相关阅读:
    二维莫队的一个细节
    错失AK良机的测试48T3 Walk
    枚举二进制子集
    又是一次值得纪念的考试
    测试46
    值得纪念的测试43
    点分治模板理解
    牛客多校第三场 G Removing Stones(分治+线段树)
    牛客多校第三场 F Planting Trees
    HDU6621 K-th Closest Distance HDU2019多校训练第四场 1008(主席树+二分)
  • 原文地址:https://www.cnblogs.com/PPXppx/p/10336149.html
Copyright © 2011-2022 走看看