【题意】
电视台发送信号给很多用户,每个用户有愿意出的钱,电视台经过的路线都有一定费用,求电视台不损失的情况下最多给多少用户发送信号。【解题方法】
裸的树形DP了。
dp[i][j]代表i节点为根节点的子树j个用户的时候最大剩余费用。则dp[i][j] = max(dp[i][j], dp[i][k]+dp[son][j-k]-w[i][son]);
【AC 代码】
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 3005;
int dp[maxn][maxn],head[maxn],tot;
int num[maxn],f[maxn];
struct edge{
int to,next,w;
}E[maxn*2];
void init(){
memset(head,-1,sizeof(head));
tot=0;
}
void addedge(int u,int v,int w){
E[tot].to=v,E[tot].w=w,E[tot].next=head[u],head[u]=tot++;
}
void dfs(int u,int fa)
{
if(num[u]) f[u]=1;
for(int i=head[u]; ~i; i=E[i].next){
int v=E[i].to,w=E[i].w;
if(v==fa) continue;
dfs(v,u);
f[u]+=f[v];
for(int j=f[u]; j>=0; j--){
for(int k=0; k<=j; k++){
dp[u][j] = max(dp[u][j],dp[u][j-k]+dp[v][k]-w);
}
}
}
}
int main()
{
int n,m;
while(scanf("%d%d",&n,&m)!=EOF)
{
init();
int k,a,b;
for(int i=1; i<=n-m; i++){
scanf("%d",&k);
while(k--){
scanf("%d%d",&a,&b);
addedge(i,a,b);
addedge(a,i,b);
}
}
memset(num,0,sizeof(num));
for(int i=1; i<=n; i++){
dp[i][0]=0;
for(int j=1; j<=m; j++){
dp[i][j]=-inf;
}
}
for(int i=n-m+1; i<=n; i++){
scanf("%d",&num[i]);
dp[i][1]=num[i];
}
int ans;
dfs(1,-1);
for(int j=m; j>=0; j--){
if(dp[1][j]>=0){
ans=j;
break;
}
}
printf("%d\n",ans);
}
return 0;
}