要点
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
const int maxn = 3005;
int n, m, Cost[maxn];
int f[maxn][maxn], size[maxn];
vector<pair<int, int>> adj[maxn];
void dfs(int u) {
if (u > n - m) {//叶子
size[u] = 1;
f[u][1] = Cost[u];
}
f[u][0] = 0;
for (auto son : adj[u]) {
int v = son.first, c = son.second;
dfs(v);
size[u] += size[v];
for (int j = size[u]; j; j--) {//必须倒序,背包其实省略了一维[i]
for (int k = 0; k <= min(j, size[v]); k++) {//当前子树选几个
f[u][j] = max(f[u][j], f[v][k] + f[u][j - k] - c);
}
}
}
}
int main() {
scanf("%d %d", &n, &m);
for (int u = 1, k, v, cost; u <= n - m; u++) {//建图
for (scanf("%d", &k); k; k--) {
scanf("%d %d", &v, &cost);
adj[u].emplace_back(v, cost);
}
}
for (int u = n - m + 1; u <= n; u++) {//叶子的值
scanf("%d", &Cost[u]);
}
memset(f, 0xcf, sizeof f);//-inf
dfs(1);
for (int i = n; ~i; --i)
if (f[1][i] >= 0) {//不亏本
printf("%d\n", i);
break;
}
}