定义
树形依赖动态规划一般为背包问题,依赖就是指儿子依赖于父亲的树形动态规划,一般形式为只有选择了父亲节点才能选择儿子节点,对于这一种特殊的树形动态规划,有一种时间复杂度十分优秀的的方法可以解决此类问题。
举个例子
先来一道例题,给出一棵有
n
个点的树,
普通做法
设
fi,j
表示选择以
i
为根的这一棵子树,花费了
由于每次合并的复杂度为
M2
,总共合并
N
次,所以总时间复杂度为
{
int i,j,l,k;
fo(i,1,g[o])dg(son[o][i]);
fo(i,1,g[o])
fd(j,m-P[o],P[son[o][i]])
fo(l,P[son[o][i]],j)
f[o][j]=max(f[o][j],f[son[o][i]][l]+f[o][j-l]);
fd(i,m,P[o])f[o][i]=f[o][i-P[o]]+V[o];
}
特殊做法
上述做法显然会超时。
我们分析一下为什么这样做时间复杂度这么大了,每一次合并的时间复杂度为
M2
,如果可以每次转移都能做到
M
的时间复杂度,那总时间复杂度就是
首先求出整棵树的
dfs
序,并求出以
i
为根的字数大小
设
fi,j
表示选到 第
i
个点时花费的代价为j时所能获得最大的价值,第
按照
dfs
序从后往前做,如果当前点i不选,则第一个转移为
fi,j
=
fi+sizei,j
,表示继承它后一个兄弟的状态(兄弟即指它父亲的其他儿子)。
如果当前选择第
i
个点,则从
给出一张转移的简略草图,帮助理解。
注,黄色线表示第一种转移,即不选择第i个点的转移,红色线为第二种转移。