by luogu

大致题意:给出一棵树,求在一定费用下能够达到最多叶子数。

emmm...一道树上背包(多重

从树形dp思路来考虑状态的设置:

dp[i][j] -->以i节点为根,选j个用户

我们不难发现我们需要预先知道儿子状态,所以我们dfs

套个多重背包的模版,然后dfs注意下状态转移

 

#include<bits/stdc++.h>

using namespace std;
const int N=3e3+7;

int n,m;
//i为根节点节点j为费用,dp[y][j]=max(dp[y][k]dp[x][j-k] )
//dp[x][j] dp[y][k] ---> dp[x][j+k]
int dp[N][N],val[N];
int head[N],nxt[10000010],to[10000010],edge[10000010];

int _;
void add(int x,int y,int z)
{
    _++;
    to[_]=y;
    edge[_]=z;
    nxt[_]=head[x];
    head[x]=_;
    return ;
}

int dfs(int x)
{
    if(x>n-m)
    {
        dp[x][1]=val[x];
        return 1;
    }
    int re=0;
    
    for(int i=head[x];i;i=nxt[i])
    {
        int y=to[i],z=edge[i];    
        
        int v=dfs(y);
        re+=v;
        for(int j=re;j>=1;j--)
        {
            for(int k=1;k<=v;k++)
            if(j-k>=0)    
                dp[x][j]=max(dp[x][j],dp[y][k]+dp[x][j-k]-z);
                        
        }
    }
    
    return re;
}

int main()
{  
    ios::sync_with_stdio(false);
    cin>>n>>m;
    memset(dp,-0x3f, sizeof(dp));

    for(int i=1;i<=n-m;i++)
    {
        int num;
        cin>>num;
        for(int j=1;j<=num;j++)
        {
            int q,w;
            cin>>q>>w;
            add(i,q,w);
        }
    }
    for(int i=n-m+1;i<=n;i++)
    cin>>val[i];
    for(int i=1;i<=n;i++)
    dp[i][0]=0;
    
    dfs(1);
    
    for(int i=m;i>0;i--)
    {
        if(dp[1][i]>=0)
        {
            cout<<i;
            return 0;
        }
        
    }

    return 0;
}