zoukankan      html  css  js  c++  java
  • AcWing 1074 . 二叉苹果树

    题目传送门

    一、题目描述

    给定一棵含有 \(n\) 个结点的树,树根编号为 \(1\),且树上的每条边有一个边权 \(w_j\)

    要求我们只保留树中的 \(m\) 条边,使得 树根 所在的 连通块 的所有边 边权之和 最大

    二、题目分析

    想复习一下 背包\(DP\) 的同学,可以看看我之前写过的这篇 背包DP合集
    这篇题解对于重复部分的知识不会再额外讲了QwQ

    这题的题面其实就是 有依赖的背包 模型,不同的是把 物品价值 分给了 而不是

    不过,对于一棵树来说,任意节点的入边连向父节点的边) 都是 唯一

    所以 边权点权 在确定树的 根节点 以后,是可以视作一个东西的(入边价值 视作 该点价值

    常用的 有依赖的背包DP 集合划分方案有两个:

    对于本题来说,分组背包集合划分 会超时,因此采用 体积集合划分方案

    闫氏DP分析法

    是有依赖背包问题的改编 https://www.acwing.com/solution/AcWing/content/8021/

    树枝上苹果的数量可以理解成该边的权值

    状态表示
    \(f[u][j]\):表示所有以\(u\)为树根的子树中选,选\(j\)条边的最大价值

    状态计算
    每一棵子树看出一组背包,若需要选择该子树\(son\),则根结点\(u\)到子树\(son\)的边一定用上,因此能用上的总边数一定减1,总共可以选择\(j\)条边时,当前子树\(son\)分配的最大边数是\(j - 1\),对于任意一棵子树有

    \(f[u][j] = max(f[u][j], f[u][j - 1 - k] + f[son][k]+ w[i])\)

    其中: \(k∈[0,j−1]\)

    \(Code\)
    时间复杂度: \(O(N×V×V)\)

    #include <bits/stdc++.h>
    
    using namespace std;
    const int N = 110;
    const int M = N * 2;
    int n;          //表示树的节点数
    int m;          //表示要保留的树枝数量(背包容量)
    int h[N], e[M], w[M], ne[M], idx;
    int f[N][N];
    
    //邻接表模板
    void add(int a, int b, int c) {
        e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
    }
    
    //树形DP+无向图
    void dfs(int u, int father) {
        for (int i = h[u]; ~i; i = ne[i]) { //物品组
            if (e[i] == father)continue;    //不走回头路
            dfs(e[i], u);           //计算子分枝
            //分组背包
            for (int j = m; j; j--)         //枚举u结点剩余体积
                for (int k = 0; k < j; k++) //在这样的情况下,分给子树e[i]多大的体积?枚举体积预留一条连向父节点的边
                    //f[e[i]]-->son 子树
                    f[u][j] = max(f[u][j], f[u][j - 1 - k] + f[e[i]][k] + w[i]);
        }
    }
    
    int main() {
        //邻接表初始化
        memset(h, -1, sizeof h);
        cin >> n >> m;
        //读入n-1条边
        for (int i = 1; i < n; i++) {
            int a, b, c;
            cin >> a >> b >> c;
            //建立无向图
            add(a, b, c), add(b, a, c);
        }
        //有依赖的背包树形dp
        dfs(1, -1);
        //输出
        printf("%d", f[1][m]);//以1号节点为根,边数不超过m(最大背包上限)的最大值
        return 0;
    }
    
  • 相关阅读:
    Borladn传奇终结巨人倒下了
    C#数据导出到excel
    ADO.NET Entity Framework学习笔记(4)ObjectQuery对象
    ADO.NET Entity Framework学习笔记(3)ObjectContext对象[转]
    在Vista,WIN2K8下IE7.0就不能正常访问asp.net development server解决办法
    获取SQL Server表字段的各种属性
    白话说.net事件和委托
    Ado.Net Entity : Object doesn’t display linked members (foreign keys)
    移动飞信WEB发送服务接口
    asp.net FormsAuthentication 认证
  • 原文地址:https://www.cnblogs.com/littlehb/p/15788100.html
Copyright © 2011-2022 走看看