树形背包

动态规划 树形背包

树形背包

树形背包的实现与普通01背包并无二样

eNVVHS.png

树形背包复杂度优化

当然,假如单纯是树形背包的话是不值得单独开一篇博客作记录的

尝试口胡分析一下复杂度:对于每一个节点,都要枚举其节点的子树大小次(第一层for);转移过程中,还需要遍历该节点的每一子树,并枚举其子树大小次(第二层次for),因此总复杂度为\(O(n^3)\).好像OI界里复杂度如此优秀的同时还上得了台面的只有同复杂度的floyd吧( ̄_ ̄|||)尝试进一步去优化流程

发现每一次遍历子树时,其实并不需要完整地枚举父节点的"完整"大小。想象一下,父节点是随着子节点的更新而不断扩大的

eNeVYQ.png

eNeb1s.png

eNuyhF.png

依次类推...更加通用的伪代码如下:

node u;
int size=0;
for(v=son of v){
	dfs(v);
	for(int i=0;i<=size;++i){
		for(int j=0;j<=sizeof(v);++j){
			f[i+j]=max(f[i]+f[j]+trans..)
		}
	}
    size+=sizeof(v);
}

再次尝试口胡证明一下复杂度:依旧是递归每一个节点,但是枚举次数被大大缩短(第一层for);利用子树进行更新的复杂度没变(第二层for)..因此..是\(O(n^2)\)!(老师提出的结论就是这样的ㄟ( ▔, ▔ )ㄏ)

例题

CF 815C Karen and Supermarket

C. Karen and Supermarket

会发现将优惠序列连接起来会构成一棵树:

  1. 有n个节点和n-1条边
  2. 每一个节点只能向标号更小的节点连边,这一条性质保证了不会分裂成森林,也不会构成

令 f[i][j][0/1] 表示以i为根的子树中,购买 j 件物品的最小花费, 根节点(0/1)使用 / 不使用 优惠券。得到递推转移方程式如下:

\[f[u][i+j][0]=min(f[u][i][0]+f[v][j][0]) \]

\[f[u][i+j][1]=min(f[u][i][1]+f[v][j][1]) \]

\[f[u][i+j][1]=min(f[u][i][1]+f[v][j][0]) \]

倘若直接立方级的转移的话是tle的,加上小优化边dfs边dp即可ac。 (一遍ac祭φ(゜▽゜*)♪)

P3177 [HAOI2015]树上染色

P3177 [HAOI2015]树上染色

一个稍微复杂一点的树形背包。令f[i][j]表示以i为根节点的子树中有j个黑点。考虑每一条边对答案的贡献:

eNQFwq.png

得到状态转移方程:

\[f[u][i+j]=max(f[u][i]+f[v][j]+边的贡献) \]

撒花★,°:.☆( ̄▽ ̄)/$:.°★

posted @ 2020-06-29 21:49  ticmis  阅读(314)  评论(0)    收藏  举报