有依赖的背包

问题描述:

解法:

这种树形的结构我们首先很容易去想到 树形dp ,但是和 树形dp 不一样的地方在于它选一个节点的话还有附加条件(也就是依赖关系)

我们对于每一个节点可以把它看成一个分组背包

dp[i][j] 代表 选第 i 个节点 背包容量为 j 的时候 背包的最大价值

我们可以先采取 树形dp 的方法去更新叶子节点,然后更新父亲节点

更新父亲节点的状态转移方程也很好想:

dp[i][j] = max(dp[i][j],dp[son][k]+dp[i][j-k])

int n,m;
int h[110],e[110],next[110],cnt;
int v[110],w[110],dp[110][110];

void add(int a,int b) {
    e[cnt] = b;
    next[cnt] = h[a];
    h[a] = cnt++;
}

void dfs(int u) {
    for (int i = h[u];i != -1;i = next[i]) {
        int son = e[i];
        dfs(son);
        for (int j = m-v[u];j >= 0;j--) {  // 因为必须如果选了孩子必须选父亲,先把父亲的位置空出来
            for (int k = 0;k <= j;k++) {
                dp[u][j] = std::max(dp[u][j],dp[u][j-k]+dp[son][k]);
            }
        }
    }
    // 更新叶子
    for (int i = m;i >= v[u];i--)
        dp[u][i] = dp[u][i-v[u]] + w[u];
    for (int i = 0;i < v[u];i++)
        dp[u][i] = 0;
}

int main() {
    memset(h,-1, sizeof(h));
    cin >> n >> m;
    int root;
    for (int i = 1;i <= n;i++) {
        int p;
        cin >> v[i] >> w[i] >> p;
        if (p == -1)
            root = i;
        else
            add(p,i);
    }
    dfs(root);
    cout << dp[root][m] << endl;
    return 0;
}
原文地址:https://www.cnblogs.com/-Ackerman/p/12252668.html