Loading

后序遍历优化树形背包

学习资料

大致精神是, 我们先对原来的树进行后序遍历重编号, 然后定义状态 \(f(i,k)\) 为选取前 \(i\) 个物品, 背包容量为 \(k\) 的最大价值.

后序遍历的好处是, 每次新加的点都是子树的根, 并且子树内的顺序在值域上连续.
于是讨论是否选择当前的点 \(i\), 状态转移方程即为:

\[f(i,k)=\max(f(i-1,k-w_i)+v_i,f(i-\text{size}_i,w_i)) \]

时间复杂度 \(O(nW)\).

code:

void dfs(int u,int f)
{
	siz[u]=1;
	for(int i=h[u];i;i=e[i].nxt)
	{
		int p=e[i].to;
		if(p==f)continue;
		dfs(p,u);
		siz[u]+=siz[p];
	}
	dfn[++dfncnt]=u;
}
//-----------------------------------------------------------------
for(int i=1;i<=rtcnt;i++)dfs(rt[i],0);
for(int i=1;i<=n;i++)
	for(int j=0;j<=W;j++)
	{
		int u=dfn[i];
		dp[i][j]=dp[i-siz[u]][j];
		if(j>=w[u])dp[i][j]=max(dp[i][j],dp[i-1][j-w[u]]+v[u]);
	}
posted @ 2022-10-23 20:22  pjykk  阅读(48)  评论(0编辑  收藏  举报