题解 P1273 【有线电视网】
背包类树形dp。本题需要运用分组背包模型。
首先定义状态:
可以将选择的用户个数看作背包的容量维度,将获得的利润看作背包的价值维度。可以设计出如下的状态转移:
其中,
注意细节处理。代码如下:
#include<bits/stdc++.h>
using namespace std;
struct Edge{
int v,w,nxt;
}mem[3005*2];
int head[3005],cnt;
int size[3005];
inline void AddEdge(int u,int v,int w){
mem[++cnt].v=v;
mem[cnt].w=w;
mem[cnt].nxt=head[u];
head[u]=cnt;
}
int N,M;
int leaf[3005];
int f[3005][3005];
inline void dfs(int u){
if(leaf[u]){
f[u][1]=leaf[u];
size[u]=1;
return;
}
for(register int i=head[u];i;i=mem[i].nxt){
int v=mem[i].v,w=mem[i].w;
dfs(v);
size[u]+=size[v];
for(register int j=M;j>=1;--j)
for(register int k=0;k<=min(size[v],j);++k)
f[u][j]=max(f[u][j],f[u][j-k]+f[v][k]-w);
}
}
int main(){
memset(f,0xcf,sizeof(f));
scanf("%d%d",&N,&M);
for(register int i=1;i<=N-M;++i){
int k;
scanf("%d",&k);
for(register int j=1;j<=k;++j){
int a,c;
scanf("%d%d",&a,&c);
AddEdge(i,a,c);
}
}
for(register int i=1;i<=M;++i) scanf("%d",&leaf[N-M+i]);
for(register int i=1;i<=N;++i) f[i][0]=0;
dfs(1);
for(register int i=M;i>=1;--i){
if(f[1][i]>=0){
printf("%d",i);
return 0;
}
}
return 0;
}