状态表示:
(dp[u][j]):以(u)为根的子树上有(j)个用户时的最大收益。计算结束后,使(dp[1][i] ge 0)的最大(i)就是答案。
状态转移:
[dp[u][j] = max(dp[u][j], dp[u][j-k] + dp[v][k] - w)
]
边界:
(f[u][0]=0),(f[leaf][1]=pay[leaf])。
注意点
枚举用户数和转移时需要小优化,而不能直接从总的用户数开始枚举,否则会超时。
const int N=3010;
vector<PII> g[N];
int f[N][N];
int pay[N];
int n,m;
int dfs(int u)
{
f[u][0]=0;
if(u > n-m) // 叶子
{
f[u][1]=pay[u];
return 1;
}
int sum=0;
for(int i=0;i<g[u].size();i++)
{
int v=g[u][i].fi,w=g[u][i].se;
int t=dfs(v);
sum+=t;
for(int j=sum;j>=0;j--)
for(int k=0;k<=min(t,j);k++)
f[u][j]=max(f[u][j],f[u][j-k]+f[v][k]-w);
}
return sum;
}
int main()
{
memset(f,-0x3f,sizeof f);
cin>>n>>m;
for(int i=1;i<=n-m;i++)
{
int k;
cin>>k;
while(k--)
{
int a,c;
cin>>a>>c;
g[i].pb({a,c});
}
}
for(int i=n-m+1;i<=n;i++) cin>>pay[i];
dfs(1);
for(int i=m;i>=1;i--)
if(f[1][i] >= 0)
{
cout<<i<<endl;
break;
}
//system("pause");
return 0;
}