• 【树形DP】【分组背包】【HDU1561】


    【题目来源】http://acm.hdu.edu.cn/showproblem.php?pid=1561

    【题目解析】有树形依赖的背包问题。

          流传较广的是多叉树转二叉树的DP方法。首先运用“左儿子右兄弟”的方法将多叉树转化为二叉树。这样的话,DP的进程就更加容易。由于是二叉,那么只需要枚举分配给左儿子多少个点,分配给右儿子(右兄弟)多少个点即可。不过需要注意的是枚举给左儿子的时候记得给父亲留一个点,因为是依赖的;枚举给右儿子的时候可以全部给它,因为它和父节点是兄弟关系。

          这里要解析的是直接多叉树DP,即直接在原有的树上面进行DP。从递归的角度来考虑:把根节点看成是一个容量为V背包,其所有的子树看成是物品。枚举每个子树,对于某个子树来说,先去掉这棵子树根节点的体积W,递归求出剩下的V-W容量的背包能装下这个子树的子树的物品。那么将会得到一个从0..V-W的一个01背包,把每一个体积及其对应的价值看成是一个物品,因此共有V-W+1个物品,每个物品再算上所去掉的根节点。那么新的这V-W+1个物品可以看成是一个分组,物品之间是互斥的,只能选择其一。由此可见,对于每个根节点来说,它的所有子树就可以看成是一组组的分组物品,各组内部的物品之间是互斥的,只能选择其一。所以问题最终的本质是在树上进行的分组背包。

    【代码如下】

     1 #include <iostream>
     2 #include <cstring>
     3 
     4 using namespace std;
     5 
     6 const int Max = 201;
     7 
     8 struct edge
     9 {
    10     int v;
    11     edge* next;
    12     edge(int _v, edge* _next) : v(_v), next(_next) {}
    13 }* E[Max];
    14 
    15 int N, V, F[Max][Max], C[Max];
    16 
    17 void Clear()
    18 {
    19     memset(F, 0, sizeof(F));
    20     memset(E, 0, sizeof(E));
    21 }
    22 
    23 void Dp(int i, int V)
    24 {
    25     for (edge* j = E[i]; j; j = j -> next)
    26     {
    27         int v = j -> v;
    28         Dp(v, V - 1);
    29         for (int k = V; k >= 0; k --)
    30             for (int l = 0; l < min(V, k); l ++)
    31                 F[i][k] = max(F[i][k], F[i][k - (l + 1)] + F[v][l] + C[v]);
    32     }
    33 }
    34 
    35 inline void edgeAdd(int x, int y)
    36 {
    37     E[x] = new edge(y, E[x]);
    38 }
    39 
    40 void Init()
    41 {
    42     for (int i = 1, x; i <= N; i ++)
    43     {
    44         cin >> x >> C[i];
    45         edgeAdd(x, i);
    46     }
    47 }
    48 
    49 int main()
    50 {
    51     cin >> N >> V;
    52     while (N || V)
    53     {
    54         Init();
    55         Dp(0, V);
    56         cout << F[0][V] << endl;
    57         Clear();
    58         cin >> N >> V;
    59     }
    60     return 0;
    61 }
  • 相关阅读:
    「Luogu」2831愤怒的小鸟 (DFS+dp)
    LeetCode习题集
    递归的时间复杂度你真的懂吗?不是所有的二分递归都是logn级别
    [数据结构篇]谈一谈优先队列吧!
    论文爱好者(我不是)的福利
    Python 读微博留言进行情感分析(文本分类)
    python 多进程中的p.apply_async()
    记录本科论文开题报告修改过程
    KMP字符串匹配算法
    Pandas Timedelta
  • 原文地址:https://www.cnblogs.com/GXZC/p/2851761.html
Copyright © 2020-2023  润新知