题目:有线电视网
思路:DP。f[i][j]表示根节点为i的子树中选j个叶子节点可以得到的最大利润。
代码:
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <stack>
#include <queue>
#include <deque>
#include <set>
#include <cstring>
#include <map>
using namespace std;
int n,m;
int a[3005]={0};
vector<int> vec[3005];
int v[3005]={0};
int f[3005][3005]={0};
int dfs(int x){
if(x>=n-m+1) {
f[x][1]=a[x];
return 1;
}
int s=0;
for(int i=0;i<vec[x].size();i++){
int y=dfs(vec[x][i]);
s+=y;
for(int j=s;j>0;j--){
for (int k=1; k<=j; k++){
f[x][j]=max(f[x][j],f[x][j-k]+f[vec[x][i]][k]-v[vec[x][i]]);
}
}
}
return s;
}
int main() {
scanf("%d%d",&n,&m);
for(int i=1;i<=n-m;i++){
int k;
scanf("%d",&k);
for(int j=1;j<=k;j++){
int x,y;
scanf("%d%d",&x,&y);
vec[i].push_back(x);
v[x]=y;
}
}
for(int i=n-m+1;i<=n;i++){
int x;
scanf("%d",&x);
a[i]=x;
}
memset(f,-63,sizeof(f));
for(int i=1;i<=n;i++){
f[i][0]=0;
}
dfs(1);
for(int i=m;i>=0;i--){
if(f[1][i]>=0) {
printf("%d",i);
break;
}
}
return 0;
}