有依赖的背包问题小记

前言

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

有依赖的背包问题

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

posted @ 2019-10-27 11:41  千载煜  阅读(1687)  评论(0编辑  收藏  举报