主件有花费无价值, 附件有花费有价值, 附件没有附件, 主件50个, 每个主件有10个附件, 背包容量1e6, 问最大价值.
之前做依赖背包和树上背包都是
O
(
n
V
2
)
O(nV^2)
O(nV2)的复杂度…毫无疑问会T…看了题解原来有
O
(
n
V
)
O(nV)
O(nV)复杂度的做法.
注意: 这是依赖背包的
O
(
n
V
)
O(nV)
O(nV)做法, 树上背包因为有连续依赖, 必须借助dfs(类似树形dp)的方式才能实现
O
(
n
V
)
O(nV)
O(nV), 具体见???
因为每个主件是互相独立的, 所以我们可以一个个主件(及其附件集合)地考虑.
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]表示考虑前
i
i
i个主件(及其附件集合), 花费为
j
j
j时的最大价值. 然后就是简单的状态转移.
代码:
int n, W;
int g[M];//这里用g代表临时状态, 每次更新完放回f
int f[M];//有些类似滚动数组, 其实开dp[i][j]也没有问题
vector<pii> son[66];
int pac[66];
int sonN[66];
void init() {
n = read(), W = read();
for (int i = 1; i <= n; ++i) {
pac[i] = read();
sonN[i] = read();
for (int j = 0; j < sonN[i]; ++j) {
int v = read(), w = read();
son[i].emplace_back((pii) {v, w});
}
}
for (int i = 1; i <= n; ++i) {
Mem(g, 0);
for (int j = pac[i]; j <= W; ++j)
g[j] = f[j - pac[i]];
for (auto s:son[i])
for (int j = W; j >= s.first + pac[i]; --j)
checkMax(g[j], g[j - s.first] + s.second);
for (int j = 0; j <= W; ++j)
checkMax(f[j], g[j]);
}
int ans = 0;
for (int j = 0; j <= W; ++j)
checkMax(ans, f[j]);
write(ans), enter;
}