树形DP
DP上树。
存储:边表(邻接表,链式前向星)
(找节点i的子树大小)
状态设计:每个节点为状态;初始化:叶子节点为1;转移:把儿子们加起来。
顺序:从叶子节点不断向上做到根的过程。
void dfs(int now ,int fa){
for(int p = head[now];p;p = edge[p].nxt){
if(edge[p].nxt != fa){
dfs(edge[p].to,now);
f[now] += f[edge[p].to];
}
}
}
求树的直径
规定一棵树,输的诗经就是在树上找到两个点,使其距离最长,距离即直径。
思考可得:距离 = (p_1 => lca(p_1,p_2) => p_2)
枚举以每个点作为拐点的最长路径,最后对每个拐点去max。要算以i向下的最长路,以i向下的次长路,分别用f[],g[]。
初始化:f[i]、g[i] = 0
求树上所有路径的总长度和
求树上路径的总长度和
g[i]所有点到根节点的距离之和,f[i]表示答案。p1到i的路径总和为:g[i] = (g[p1] + size[p1]) * (size[i] - size[p1])(size是子树的大小)。
或者:
询问树的最大独立集
选出更多的点,使得这些点互不相邻。(没有边)
f[i][0/1]表示i这个点选/不选的方案数。
士兵
现在要在一棵树上布置士兵,每个士兵在结点上,每个士兵可以守护其结点直接相连的全部边,问最少需要布置多少个士兵。
f[i][0/1/2],对于节点i,0表示儿子保护,1表示自己保护,2表示父亲保护。
初始化叶节点:f[i][0] = INF,f[i][1] = 1,f[i][2] = 0;
g[k][0/1]:i节点的前k个儿子是不是已经有一个儿子放了士兵
依赖背包问题
依赖背包问题
每个物品要选必须先选某个指定的物品问能够获得的最大价值(今明的预算方案)
把依赖关系用数连起来,f[i][j]表示i的子树用了j的体积。
初始化:f[i][0] = 0,f[i][vi] = wi,f[i][j] = -INF
转移:g[i][j]前i个儿子用掉了前j的体积,则g[0][0],g[0][j] = -INF,g[i][j] = max(g[i-1][j-k] + f[pi][k])就是前i个儿子用掉j个体积的最大价值。(逐渐跑题)
转移:f[i][0] = 0;f[i][j] = g[r][j-vi] + wi;
复杂度(n * m^2)