P1040 加分二叉树

P1040 加分二叉树

加分二叉树或许是你在考场上做完这道题就会加分的一棵神奇的树,就像AC自动机一样amazing

 

前置知识

1.前序遍历: 根结点在最前       即  头 左 右

2.中序遍历:根结点在中间        即  左 右 头

3.后序遍历:根结点在最后        即  左 右 头

 

 

理解一下题意(在这里栽了个大坑)

      题目给出一个树的中序遍历,要在这个中序遍历的条件限制下,得到最大加分,并且输出此时的加分二叉树的前序遍历

      一定要在给出的中序遍历的条件限制下,一定一定一定

 

 

所以解答有两步

1.求最大加分

      我们可以把问题小化,也就是先求由1个数字构成加分树的最大加分,再求2个的,一直求到n个的,最大加分累加(也不算是累加)最后得到最优解

 

 

以下是错误解答

 

2.求前序遍历

   可以递归求解

   先输出根结点

  然后递归左子树

  然后递归右子树

 

 

 

 代码

1.记忆化搜索(由于这道题数据很水,所以可以擦边过,样例大了估计要WA)

#include<iostream>
#include<cstdio>
#include<algorithm> 
#include<cmath>
#include<string>
#include<cstring>
#include<cstdlib>

using namespace std;

int n,gen[31][31];
long long ans;
int a[31],dis[31][31];

int dfs(int l,int r)  //记忆化搜索 
{
    if(dis[l][r]>0) return dis[l][r];  //已经计算过加分了,直接返回 
    if(l==r) return a[l];  //单元素区间根为自己 
    if(r<l) return 1;  //空子树 
    for(int i=l;i<=r;i++)  //寻找在区间[l,r]内以那个点为根加分最大 
    {
        int p=dfs(l,i-1)*dfs(i+1,r)+a[i];
        if(dis[l][r]<p)
        {
            dis[l][r]=p;
            gen[l][r]=i;
        } 
    }
    return dis[l][r];  //得到最大加分 
}

void qianxu (int l,int r) //前序遍历:头 左 右 
{
    if(r<l) return;  //这个区间不合法 
    if(l==r) {printf("%d ",l); return;}  //该区间只有一个数 
    printf("%d ",gen[l][r]);  //
    qianxu(l,gen[l][r]-1);    //
    qianxu(gen[l][r]+1,r);    //
    
}

int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        dis[i][i]=a[i]; //初始化,单元素区间加分为自己的加分 
        gen[i][i]=i;  //单元素区间的根为自己
    }
    ans= dfs(1,n);   //区间[1,n]的加分 
    printf("%ld\n",ans);
    
    qianxu(1,n);  //递归出结果 
    
    return 0;
}

 

 2.区间DP

   注意此处是在开区间的大前提下进行

#include<iostream>
#include<cstdio>
#include<algorithm> 
#include<cmath>
#include<string>
#include<cstring>
#include<cstdlib>

using namespace std;

int n,a[35],gen[35][35];
int dp[35][35];   // dp[l][r],gen[l][r] ->ans in [l,r) 

int dfs(int l,int r) 
{
    printf("%d ",gen[l][r]);  //
    if(gen[l][r]>l)           //
      dfs(l,gen[l][r]);
    if(gen[l][r]+1<r)         //
      dfs(gen[l][r]+1,r);
}

int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
       scanf("%d",&dp[i][i+1]);
       gen[i][i+1]=i;
       dp[i][i]=1;     //空子树 
    }
    
    for(int l=2;l<=n;l++)  //枚举区间长度 
       for(int i=1;i<=n-l+1;i++)  //区间起点 
        {
            int j=i+l;    //区间终点 
            for(int k=i;k<j;k++)  //枚举根结点 
            {
                if(dp[i][j]<dp[i][k]*dp[k+1][j]+dp[k][k+1])  //更新最大加分 
                {
                    dp[i][j]=dp[i][k]*dp[k+1][j]+dp[k][k+1];
                    gen[i][j]=k;
                }    
            }
        } 

    printf("%d\n",dp[1][n+1]);
    
    dfs(1,n+1);  //开区间递归出答案 
        

    return 0;
}

 

 

感悟

1.不要手误打错输出格式,哪里加&,哪里不加&,输出的时候加了那就会输出存储空间

2.检查一下for循环的条件OK???

 

posted @ 2019-06-10 16:21  晔子  阅读(219)  评论(0编辑  收藏  举报