P2515 [HAOI2010]软件安装

题意

给你\(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

猜你喜欢

转载自www.cnblogs.com/Garen-Wang/p/10959625.html
今日推荐