zoukankan      html  css  js  c++  java
  • 有依赖的背包问题小记

    前言

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

    有依赖的背包问题

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

  • 相关阅读:
    idea 没有 persistence
    java 枚举(二) 级联关系
    java to edi 动态/静态映射
    edi to java
    C# 扩展方法
    最详细的C++对应C#的数据类型转换
    c# .Net随机生成字符串代码
    遍历结构体内部元素和值(Name and Value)
    寒假学习计划
    python os.path模块
  • 原文地址:https://www.cnblogs.com/lcez56jsy/p/11747023.html
Copyright © 2011-2022 走看看