• 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
    ",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
    ",dp[1][n+1]);
        
        dfs(1,n+1);  //开区间递归出答案 
            
    
        return 0;
    }

    感悟

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

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

  • 相关阅读:
    学习进度(第十四周)
    学习进度(第十三周)
    程序员修炼之道阅读笔记03
    程序员修炼之道阅读笔记02
    学习进度(第十二周)
    冲刺进度条10
    冲刺进度条09
    冲刺进度条08
    寒假学习进度报告2
    寒假学习进度报告1
  • 原文地址:https://www.cnblogs.com/xiaoyezi-wink/p/10998391.html
Copyright © 2020-2023  润新知