树形依赖背包

例题

n n n 门课,每门课程有不同的学分,都可能有一门或没有需要先修的课程。求在 m m m 门课的前提下,能够获得的最大学分是多少。

想选一个课程,必须先选它的父亲。设 f i , j f_{i,j} fi,j 为在以 i i i 为根的子子树中,选 j j j 个点能获得的最大学分。那么可以枚举父亲和儿子的 j j j 进行转移,再求出子树大小进行优化,复杂度 O ( n 2 ) O(n^2) O(n2)

void dfs(int x, int fa) {
	sz[x] = 1;
	for (int i = head[x]; i; i = e[i].nxt) {
		int y = e[i].to;
		if (y == fa) continue;
		dfs(y, x); 
		memset(g, 0, sizeof(g)); //g 一定要初始化
		for (int j = sz[x]; j; j--) // 一定要反响枚举,避免后效性
			for (int k = sz[y]; k; k--) 
				g[j + k] = max(g[j + k], f[x][j] + f[y][k]);
		sz[x] += sz[y]; // 注意这行代码的位置
		for (int j = 1; j <= sz[x]; j++) f[x][j] = max(f[x][j], g[j]);
	}
}
  • 关于转移的枚举,这个顺序最好别改,可能改错。比如下方代码,当 j = 1 , k = 1 j = 1, k = 1 j=1,k=1 时,只能选 x x x。但可能取的是 y y y 而不是 x x x
for (int j = sz[x]; j; j--)
		for (int k = sz[y]; k > 0; k--) {
			if (j - k < 1) continue;
			f[x][j] = max(f[x][j], f[y][k] + f[x][j - k])
		}
  • 关于 g g g 数组的作用。比如 i i i j j j 都枚举 1 , 2 1,2 1,2。假设 1 1 1 1 1 1 更新了 f f f。然后枚举到了 2 , 1 2,1 2,1,那么会用到被更新的 f f f,那么儿子中的点被算了两次。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值