有依赖的背包问题小记

Posted lcez56jsy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了有依赖的背包问题小记相关的知识,希望对你有一定的参考价值。

前言

众所周知,背包是可以挂在树上的。

有依赖的背包问题

顾名思义,有依赖的背包里的物品的选择是有依赖的废话即选择一个物品,就必须先选某个物品。这个必须先选的物品我们称之为依赖物品。一般地,某个物品的依赖物品只有一个(如果有多个的话可以考虑把出题人挂在树上)(但某个物品可以同时被多个物品依赖)
首先我们得表示出来物品的依赖关系,考虑到物品i的依赖物品只有1个,所以可以用父子关系来表示,自然而然的想到用树。
对于物品i,我们要dp出以i为根的子树中,体积为j时的最大权值和。考虑i的每个儿子,(由于是从下往上dp,所以i的儿子的dp值已经算好了)我们需要考虑从以i的第j个儿子为根的子树中选几个节点,同时我们已经知道了第j个儿子的所有dp值,所以不妨把以第j个儿子为根的子树看做一组物品,且我们已经知道分配给这组物品x的体积时,最大值是多少。
所以就相当于对每个节点做分组背包。同时注意一点,在考虑以i为根的子树的时候,点i是必选的,所以i会占去1的体积。要注意这一点。
由于窝比较菜,不会直接推dp式子,所以窝采用一个辅助数组,先进行不考虑i的dp。之后再转化成真实的dp值。
还是康康蒟蒻的代码叭

void dfs(int u,int fa)
{
    sum[u]=1;
    for(int e=head[u];e;e=ed[e].nxt)
    {
        int v=ed[e].to;
        if(v==fa)continue;
        dfs(v,u);
        sum[u]+=sum[v];//sum[i]表示以i为根的子树的大小
    }
    int t=0;
    for(int e=head[u];e;e=ed[e].nxt)
    {
        int v=ed[e].to;
        if(v==fa)continue;
        zz[++t]=v;//是指针不是z z(记录i节点的第t个儿子的编号)
    }
    if(!t)
    {
        val[u][1]=zhi[u];
        return ;
    }
    memset(dp,0,sizeof(dp));//这里dp就是辅助数组,为了不WA,要每次memset一遍
    for(int i=1;i<=t;i++)//接下来就是个分组背包
    {
        for(int j=sum[u]-1;j>=0;j--)
        {
            for(int r=1;r<=sum[zz[i]];r++)
            {
                if(j-r>=0)
                 dp[j]=max(dp[j],dp[j-r]+val[zz[i]][r]);
            }
        }
    }
    for(int i=sum[u];i>=1;i--)
     dp[i]=dp[i-1]+zhi[u];//更新成真正的dp值
    for(int i=1;i<=sum[u];i++)
     val[u][i]=dp[i];
}

一点注意:注意这里zz数组一定要在dfs(v,u)之后记录。

以上是关于有依赖的背包问题小记的主要内容,如果未能解决你的问题,请参考以下文章

Consumer (有依赖的背包)

hdu_3449(有依赖背包)

有依赖的背包问题(树状dp 深搜)

luoguP1064 金明的预算方案 (有依赖的背包问题)

.NET Core 中依赖注入 AutoMapper 小记

有依赖的背包