vijos1100 加分二叉树

已知二叉树中序遍历序列,求所有可行树中的某种状态最优解。

二叉树中序遍历性质:1.遍历顺序:左节点->根->右节点。2.序列最后一个元素与深度遍历(二叉树前序遍历)时的最后一个元素相同3.同一个子树的遍历顺序是一个连续序列,此序列中的某个点都可能是该子树的根节点

dp[i][j]:[i,j]序列中的最优解。根据性质3,必须枚举所有可能的子节点。pre[i][j]:[i,j]序列子树的根节点是k

dp[i][j]=max{dp[i][k-1]*dp[k+1][j]+w[k]} pre[i][j]=k 

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<algorithm>
#include<map>
#include<vector>
#include<queue>
#define ll long long
#define sf scanf
#define pf printf
#define maxn 50
#define INF 0x3f3f3f3f
#define mem(a,b) memset(a,b,sizeof(a))
#define lowbit(x) x&(-x)
const ll mod=1000000007;
using namespace std;

int n,w[maxn],pre[maxn][maxn],dp[maxn][maxn];

void print(int i,int j){
    if(i>j) return;
    printf("%d",pre[i][j]);
    if(i!=j||i!=n) printf(" ");
    print(i,pre[i][j]-1);
    print(pre[i][j]+1,j);
}

int main(){
    scanf("%d",&n);
    mem(dp,0),mem(pre,-1);
    for(int i=1;i<=n;i++) scanf("%d",&w[i]),dp[i][i]=w[i],pre[i][i]=i;
    for(int l=1;l<=n-1;l++){
        for(int i=1;i+l<=n;i++){
            int j=i+l;
            for(int k=i;k<=j;k++){
                if(dp[i][k-1]*dp[k+1][j]+w[k]>dp[i][j]){
                    if(k-1<i) dp[i][k-1]=1;
                    if(k+1>j) dp[k+1][j]=1;
                    dp[i][j]=dp[i][k-1]*dp[k+1][j]+w[k];
                    pre[i][j]=k;
                }
            }
        }
    }
    printf("%d\n",dp[1][n]);
    print(1,n);
    printf("\n");
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值