zoukankan      html  css  js  c++  java
  • 加分二叉树

    以下内容来自洛谷:http://www.luogu.org/problem/show?pid=1040
    设一个n个节点的二叉树tree的中序遍历为(1,2,3,…,n),其中数字1,2,3,…,n为节点编号。每个节点都有一个分数(均为正整数),记第i个节点的分数为di,tree及它的每个子树都有一个加分,任一棵子树subtree(也包含tree本身)的加分计算方法如下:
    subtree的左子树的加分× subtree的右子树的加分+subtree的根的分数。
    若某个子树为空,规定其加分为1,叶子的加分就是叶节点本身的分数。不考虑它的空子树。
    试求一棵符合中序遍历为(1,2,3,…,n)且加分最高的二叉树tree。要求输出;
    (1)tree的最高加分(2)tree的前序遍历
    输入:
    第1行:一个整数n(n<30),为节点个数。
    第2行:n个用空格隔开的整数,为每个节点的分数(分数<100)。
    输出:
    第1行:一个整数,为最高加分(结果不会超过4,000,000,000)。
    第2行:n个用空格隔开的整数,为该树的前序遍历。
    样例输入:
    5
    5 7 1 2 10
    样例输出:
    145
    3 1 2 4 5
    以上内容来自洛谷:http://www.luogu.org/problem/show?pid=1040

    =================================================================================

    状态转移方程:
    f(k,k)=value[k]【1<=k<=n】
    f(i,j)=max{f(i,i)+f(i+1,j) , f(j,j)+f(i,j-1) , f(k,k)+f(i,k-1)*f(k+1,j)  } 【i<k<j】
    f(i,j)表示以i为中序遍历的最左边,j为中序遍历的最右边所组成的一棵树的最大积分。
    第一行不用解释了,就是如果这棵树只包含根节点(也就是这是叶子),那么他的积分等于自己的价值。

    第二行的max部分包括3大部分:

    第一个部分,是以最左端为根节点,剩下的部分都是右子树的情况。那么他的分数就是根节点的分数+右子树的分数(因为左子树为空)
    那么f(i,i)就是根节点的分数,f(i+1,j)就是右子树的分数
    第二个部分,是以最右端为根节点,剩下的部分都是左子树的情况。那么他的分数就是根节点的分数+左子树的分数(因为右子树为空)
    那么f(j,j)就是根节点的分数,f(i,j-1)就是右子树的分数
    第三个部分是以节点k为根节点的情况。节点k的取值范围是i和j之间,但是不包括i和j(因为这两种情况前面算过了)。
    那么分数就是根节点的分数+左子树的分数*右子树的分数。f(k,k)就是根节点的分数,f(i,k-1)是左子树的分数,f(k+1,j)是右子树的分数。

    那么有人问了,为甚么要把前两种情况分开写,而不都算作第三种情况呢?我说:如果这么算的话,f(i,j)应该初始化为1【i>j】,你想这么写就自己打循环初始化dp数组吧

    打印前序遍历:

    还有一个问题,如何打印一棵树的前序遍历呢?我们想一想,打印一棵树的某种遍历,都要找到一棵树的根节点,左子树,右子树。由于题目输入的是中序遍历,给出根节点的位置和左右边界就可以打印这棵树的前序遍历了。我们用一个root[i][j]的二维数组存储来存储中序遍历从i到j的一棵树的根节点的位置。这个数组的元素和dp数组一起更新。至于打印这棵树树,只是一个递归的事情了。

    代码:

    在dp的时候,注意要先按照中序遍历的长度搜,然后按照头结点搜,这样才是正确的(自己可以想下为什么)
    下面是Cpp代码,注释懒得写(注意dp数组就是f数组,dfs函数其实就是一个dp,这些名字我用惯了也懒得改了)

    #include <iostream>
    #include <cstring>
    using namespace std;
    int root[32][32],dp[32][32],n,a[32];
    int getmax(int i,int j)//计算dp[i][j] and root[i][j]
    {
        int ans=max(dp[i][i]+dp[i+1][j],dp[j][j]+dp[i][j-1]);
        root[i][j]=(ans==dp[i][i]+dp[i+1][j])?i:j;
        for(int x=i+1;x<=j-1;x++)
            if(ans<dp[x][x]+dp[i][x-1]*dp[x+1][j])
            {
                ans=dp[x][x]+dp[i][x-1]*dp[x+1][j];
                root[i][j]=x;
            }
        return ans;
    }
    int printTree(int l,int r)//打印 中序遍历左端为l 右端为r的树
    {
        if(l<=r)
        {
            cout << root[l][r] << ' ';
            printTree(l,root[l][r]-1);
            printTree(root[l][r]+1,r);
        }
    }
    void dfs()//动态规划过程,dfs个毛啊
    {
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=n;i++)
        {
            dp[i][i]=a[i];
            root[i][i]=i;
        }
        for(int d=1;d<n;d++)//d是长度
            for(int i=1;i<=n-d;i++)
                dp[i][i+d]=getmax(i,i+d);
    }
    int main()
    {
        cin >> n;
        for(int i=1;i<=n;i++)
            cin >> a[i];
        dfs();
        cout << dp[1][n] << endl;
        printTree(1,n);
        cout << endl;
        return 0;
    }
  • 相关阅读:
    c++函数模板
    C++左移运算符重载
    and or bool and a or b 原理解释
    Python的垃圾回收机制
    《C++ 101条建议》学习笔记——第一章快速入门
    在应用中嵌入Python:转
    使用C++扩展Python的功能 转自:http://blog.csdn.net/magictong/article/details/8897568#comments
    python扩展实现方法--python与c混和编程 转自:http://www.cnblogs.com/btchenguang/archive/2012/09/04/2670849.html
    python文件头的#-*- coding: utf-8 -*- 的作用
    Pythhon 字典 key in dict 比 dict.has_key (key)效率高 为什么?
  • 原文地址:https://www.cnblogs.com/oier/p/5823629.html
Copyright © 2011-2022 走看看