有依賴的背包問題小記


前言

眾所周知,背包是可以掛在樹上的。

有依賴的背包問題

顧名思義,有依賴的背包里的物品的選擇是有依賴的廢話即選擇一個物品,就必須先選某個物品。這個必須先選的物品我們稱之為依賴物品。一般地,某個物品的依賴物品只有一個(如果有多個的話可以考慮把出題人掛在樹上)(但某個物品可以同時被多個物品依賴)
首先我們得表示出來物品的依賴關系,考慮到物品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)之后記錄。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM