有依赖的背包问题

10. 有依赖的背包问题 - AcWing题库

考虑树形 DP

假设我们对于 \(u\),已经计算完毕子节点 \(v\),那么我们应该如何合并方案呢?

有一种方式是指数级枚举子节点的所有选择方案,但是肯定不可行。

回忆一般背包的状态表示,我们可以直接搬过来用:令 \(f[u,j]\) 表示 \(u\) 为根的子树内,共 \(j\) 体积能产生的贡献。

由于以 \(u\) 为根的子树内 \(u\) 必须选择,可以先减去 \(v[u]\),做一遍 DP,然后最后增加回来即可。

对于每棵子树相互独立,且每棵子树只能选择 \(f[v][0\sim m-v[u]]\),这就是一个分组背包问题了。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define Ed for(int i=h[x];~i;i=ne[i])
#define Ls(i,l,r) for(int i=l;i<r;++i)
#define Rs(i,l,r) for(int i=l;i>r;--i)
#define Le(i,l,r) for(int i=l;i<=r;++i)
#define Re(i,l,r) for(int i=l;i>=r;--i)
#define L(i,l) for(int i=0;i<l;++i)
#define E(i,l) for(int i=1;i<=l;++i)
#define W(t) while(t--)
#define Wh while

const int N=310,M=N;
int n,m;
int h[N],e[M],ne[M],idx,v[N],w[N],f[N][N],tmp[N];//don't forget memset h!
void add(int a,int b){
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void dfs(int x,int fa){
    int mm=m-v[x],val=w[x];
    Ed{
        int v=e[i];
        if(v==fa)continue;
        dfs(v,x);
        Re(j, mm, 0)
            E(k, j)f[x][j]=max(f[x][j],f[x][j-k]+f[v][k]);
    }
    Re(j, m, v[x])f[x][j]=f[x][j-v[x]]+val;
    L(j, v[x])f[x][j]=0;
}
int main(){
    #ifndef ONLINE_JUDGE
    freopen("1.in","r",stdin);
    #endif
    scanf("%d%d",&n,&m);
    memset(h,-1,n*4+4);
    int rt;
    E(i, n){
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        ~c?add(c,i),0:rt=i;
        v[i]=a,w[i]=b;
    }
    dfs(rt,-1);
    printf("%d",f[rt][m]);
    return 0;
}
posted @ 2023-08-28 09:09  wscqwq  阅读(8)  评论(0编辑  收藏  举报