[OI] 树上背包问题

树上背包问题的使用场景

当一个问题满足树的结构,而且需要让我们选取某些边或某些点,使权值取到最值。这样的问题是树上背包问题.

树上背包模板

树上背包问题使用dfs.
一般来说,树上背包问题的基本框架如下图:

void dfs(int s){
	for(i:遍历s的全部子节点){
		dfs(i);
		for(j:背包容量倒序遍历(01背包问题时)){
			for(k:0~j-1){
				f[s][j]=max/min(f[s][j],f[i.to][k]+f[s][j-k-v[root]]+i.w);
			}
		}
	}
}

可能有些难懂,下面来做些解释:

  • 定义 f[i][j] 为以 i 为根节点,背包容量为 j 时的最大权值.
  • 树上背包问题,依照背包问题的遍历方法,通常采用三层遍历,其中:第一层遍历全部子节点,第二层遍历背包容量.
  • 树上背包问题中,一棵树的全部容量要分为根结点占用的容量各个子树占用的容量,因此,第三层遍历当前子树占用当前树的容量.
  • 注意第三层循环中 k 最小是 0 ,即一个都不分配,而最大值只能到 jv[root] ,因为还要留一个分配给根节点.
  • 已知第三层遍历占用了 k 容量,权值在之前的dfs中已求出,应为 f[i.to][k] (这里 i.to 指子节点的根节点). 而根节点占用的容量为 v[root], 权值为 i.w. 所以,剩下没被占用的总容量为 jkv[root] ,其权值我们其实可以这样表示: f[s][jkv[root]] (因为该值事先已求出),因此,得到状态转移方程为:

f[s][j]=f[i.to][k]+f[s][jkv[root]]+i.w

  • 树上背包问题的边界条件是非常需要注意的,有时限制边界条件可以节省时间,或者避免越界.
  • 建树时需要注意,该树需要是从父亲指向儿子的,否则无法快速找到子树.
  • 在无法判断父子关系时,树也可以建成一个相同形状的无向图. 在遍历时加入一个记录该次遍历父节点的参数 last 并添加 if(i.to==last) continue; 一句即可.

例题代码: 选课

posted @   HaneDaniko  阅读(82)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示