每日一题 P1273 有线电视网 树上分组背包
蓝色题,挣扎了一下写出来了
dp[i][j]表示i节点选择j个用户的收益最大值
最后求一下根节点收益不小于0的最大用户数量即可
#include <bits/stdc++.h>
#define MAXN 600005
#define int long long
#define endl "\n"
using namespace std;
struct EDGE
{
int to,next,w;
}edge[MAXN];
int head[MAXN],ptr;
void add_edge(int u,int v,int w)
{
edge[++ptr].to=v;
edge[ptr].w=w;
edge[ptr].next=head[u];
head[u]=ptr;
}
void add(int a,int b,int w)
{
add_edge(a,b,w);
add_edge(b,a,w);
}
int dp[3005][3005];
int val[3005];
int siz[3005];
int n,m;
void dfs(int now,int fa,int fe)
{
if(now>=n-m+1)
{
siz[now]=1;
dp[now][1]=val[now]-fe;
return;
}
for(int p=head[now];p;p=edge[p].next)
{
int to=edge[p].to;
if(to==fa)continue;
dfs(to,now,edge[p].w);
siz[now]+=siz[to];
for(int i=siz[now];i>=1;i--)
for(int j=1;j<=min(siz[to],i);j++)
dp[now][i]=max(dp[now][i],dp[now][i-j]+dp[to][j]);
}
for(int i=siz[now];i>=1;i--)
dp[now][i]-=fe;
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n>>m;
memset(dp,0xc0,sizeof(dp));
for(int i=0;i<3005;i++)
dp[i][0]=0;
for(int i=1;i<=n-m;i++)
{
int t;cin>>t;
for(int j=1;j<=t;j++)
{
int a,c;cin>>a>>c;
add(i,a,c);
}
}
for(int i=1;i<=m;i++)
cin>>val[n-m+i];
dfs(1,1,0);
for(int i=m;i>=0;i--)
if(dp[1][i]>=0)
{
cout<<i;
break;
}
}