题意
给你\(n\)个可能有依赖关系的物品,物品的价值为\(v_i\),重量为\(w_i\),背包大小为\(m\),要使装的物品价值最大。
做法
如果确保这些依赖关系一定是棵树的话,那么我们就可以愉快地进行树形dp。
这里复习一下树形dp:这里设\(dp[u][j]\)表示以\(u\)为根的子树中装了重量为\(j\)的最大价值。
在dfs的时候顺便更新:
\[dp[u][j] = max(dp[u][j - k], dp[v][k])\]
给出代码康康8:
void dfs(int u) {
for(int i = weight2[u]; i <= m; i++) dp[u][i] = value2[u];
for(auto v: G2[u]) {
dfs(v);
for(int j = m; j >= weight2[u]; j--) {
for(int k = 0; k <= j - weight2[u]; k++) {
dp[u][j] = std::max(dp[u][j], dp[u][j - k] + dp[v][k]);
}
}
}
}
注意:因为这里是01背包,所以在枚举\(j\)的时候照样要倒序枚举。
然而这道题不是与P2014重题的。可能出现环形依赖。
其实也很简单:环形依赖的物品,要么全选,要么都不选,我们直接缩成一个点不就完事了?
还有:就算缩点了,建出来的图也不一定是一棵树,可能是森林!
解决办法很显然(但我忘了):建立超级源点作为根,与每一颗森林的根连接,就变成了一棵树。
整体的做法就说完了。
你以为这样就完了吗?
自信满满地交上去,结果只有10pts:你缩点后的图建得不好!
我最初写的建新图是像普通缩点那样去写的,但是显然有锅:可能会有重边。
而树又不允许有重边,不然算出来的答案全错了。所以是不行的。
所以我们记录原图每个点的父亲,只要颜色不同,并且爸爸不是0,那么就连边。
最终的答案是\(dp[s][m]\)。
代码就不给辣qwq