码迷,mamicode.com
首页 > 其他好文 > 详细

有依赖的背包问题小记

时间:2019-10-27 13:09:16      阅读:95      评论:0      收藏:0      [点我收藏+]

标签:max   ret   就是   需要   分配   +=   数组   表示   更新   

前言

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

有依赖的背包问题

顾名思义,有依赖的背包里的物品的选择是有依赖的废话即选择一个物品,就必须先选某个物品。这个必须先选的物品我们称之为依赖物品。一般地,某个物品的依赖物品只有一个(如果有多个的话可以考虑把出题人挂在树上)(但某个物品可以同时被多个物品依赖)
首先我们得表示出来物品的依赖关系,考虑到物品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)之后记录。

有依赖的背包问题小记

标签:max   ret   就是   需要   分配   +=   数组   表示   更新   

原文地址:https://www.cnblogs.com/lcez56jsy/p/11747023.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!