/* 想了半天没想出状态 自己还是太弱了 QAQ 题目问的是最多供给多少户 一般想法是把这个值定义为状态量 没想出来QAQ....看了看题解的状态 很机智.... f[i][j]表示i的子树 选了j个叶子的最大收益 这样 不亏本就是收益>=0 转移的话 先搜一下这个子树有几个叶子 然后枚举儿子 枚举当前儿子分几个叶子 这里的枚举顺序有套路 从大到小枚举i分几个 从小到大枚举j分几个 这样可以避免 重复选择 注意初始化 */ #include<iostream> #include<cstdio> #include<cstring> #define maxn 3010 using namespace std; int n,m,p,head[maxn],num,f[maxn][maxn],ans,c[maxn]; struct node{ int v,t,pre; }e[maxn]; void Add(int from,int to,int dis){ num++;e[num].v=to; e[num].t=dis; e[num].pre=head[from]; head[from]=num; } int Dfs(int u) { if(u>p){ f[u][1]=c[u]; return 1; } int s=0; for(int i=head[u];i;i=e[i].pre){ int v=e[i].v; int x=Dfs(v);s+=x; for(int j=s;j>=1;j--) for(int k=1;k<=x;k++) f[u][j]=max(f[u][j],f[u][j-k]+f[v][k]-e[i].t); } return s; } int main() { scanf("%d%d",&n,&m);p=n-m; for(int i=1;i<=p;i++){ int x,y,z; scanf("%d",&x); for(int j=1;j<=x;j++){ scanf("%d%d",&y,&z); Add(i,y,z); } } for(int i=p+1;i<=n;i++) scanf("%d",&c[i]); memset(f,-127/3,sizeof(f)); for(int i=1;i<=n;i++) f[i][0]=0; Dfs(1); for(int i=0;i<=m;i++) if(f[1][i]>=0)ans=max(ans,i); printf("%d\n",ans); return 0; }
原文:http://www.cnblogs.com/yanlifneg/p/5831446.html