• 多叉树转二叉树有依赖的背包问题解法


    一、多叉树的定义

    多叉树即为子结点有任意个的树,而在转换时所涉及的多叉树是一棵有序的多叉树,也就是其子结点的顺序是不能够随便交换的。

    二、二叉树的定义

    二叉树是每个结点最多有两个后件,且子树有左右之分(次序不能任意颠倒)。

    三、多叉树转二叉树的作用

    在用数组等表示或保存多叉树时,会浪费存储的空间,而且由于树中每个结点的度各不相同,在搜索过程中会比较的困难。而二叉树相对于多叉树便有了这些方面的优势,能够节省浪费的存储空间,又能使搜索变得简便快捷。因此可以通过将多叉树转换成为二叉树从而实现优化。

    四、转换规则

    将一棵多叉树转换成二叉树,我们遵循的原则是:左儿子,右兄弟

    算法描述:将多叉树的第一个儿子结点作为二叉树的左结点,将其兄弟结点作为二叉树的右结点。

    假设多叉树为T,新转化的二叉树为\(K\)

    • \(T\)中的结点与\(K\)中的结点一一对应。
    • \(T\)中的某个结点\(N\)的第一个子结点为\(N_1\),则\(K\)\(N_1\)\(N\)的左儿子结点
    • \(T\)中的某个结点\(N\)的第\(i\)个子结点记为\(N_i\)(除第一个子结点),则\(K\)\(N_i\)\(N_{i-1}\)的右儿子结点(\(N_2\)\(N_1\)的右儿子结点,\(N_3\)\(N_2\)的右儿子结点)

    五、转换示意图

    六、具体实现代码

    AcWing 10. 有依赖的背包问题

    #include <bits/stdc++.h>
    
    using namespace std;
    const int N = 105;
    int n;          //物品个数
    int m;          //背包容量
    int v[N];       //物品的体积
    int w[N];       //物品的价值
    int p;          //依赖的物品编号
    int root;       //根节点
    
    //多叉树转二叉树
    int l[N], r[N]; //左儿子,右兄弟
    int son[N];     //记录i的目前输入的最后一个儿子是谁,为了后面再有其它儿子加入时,放到最后一个儿子的右子树上
    
    /*i表示结点,j表示体积,f[i][j]表示i及其兄弟结点组合不超过体积j的最大价值。由于根结点没有兄弟结点,故f[root][v]
    表示体积不超过v的最大价值*/
    int f[N][N];
    
    /**
     * 功能:计算以i及其兄弟结点组合,体积不超过j的最大价值
     * @param i 根
     * @param j 体积
     * @return 最大价值
     */
    int dfs(int i, int j) {
        if (i == 0 || j == 0) return 0; //递归出口,i=0:比如一个结点没有左儿子,默认就是i=0;
        if (f[i][j]) return f[i][j];    //记忆化
        //右子树,也就是兄弟们的最大值
        f[i][j] = dfs(r[i], j);
        //计算以自己为根的子树最大值(需要预留出v[i]的空间出来)并PK兄弟们的最大值
        for (int k = 0; k <= j - v[i]; k++)//遍历所有可能的空间
            //如果要了i结点,那么结果可能来自三方面:左子树,右子树,自己的w[i]
            f[i][j] = max(f[i][j], dfs(r[i], k) + dfs(l[i], j - v[i] - k) + w[i]);
        //返回最大值
        return f[i][j];
    }
    
    int main() {
        cin >> n >> m;
        for (int i = 1; i <= n; i++) {
            //体积,价值,依赖的物品编号
            cin >> v[i] >> w[i] >> p;
            //将录入的多叉树转为二叉树,方便查找
            if (p == -1) root = i;//记录根节点
            else {
                if (son[p] == 0) l[p] = i; //p还没有录入过儿子,那么记录p的左儿子=i
                    //如果p录入过儿子,那么需要找出它最后一个儿子是son[p],
                    // 将i记录到最后一个儿子的右结点上r[son[p]]=i
                else r[son[p]] = i;
                son[p] = i;                //修改p的最后一个儿子为i
            }
        }
        //深搜
        cout << dfs(root, m) << endl;
        return 0;
    }
    
    
  • 相关阅读:
    让你成功安装vscode中go的相关插件
    初学者没有搞明白的GOROOT,GOPATH,GOBIN,project目录
    java Concurrent包学习笔记(一):ExecutorService
    mysql主从复制(收藏)
    java Concurrent包学习笔记(三):ReentrantLock
    myBatis中if test 字符串注意事项
    mybatis标签
    安装docker跨主机网络flannel
    正则:数字字母下划线组合,长度6-10;至少包含一个大写字母、一个小写字母、一个数字
    shell [] [[]]的区别(转)
  • 原文地址:https://www.cnblogs.com/littlehb/p/15849333.html
Copyright © 2020-2023  润新知