感觉就是很普通的树形dp。
dp[ i ][ 0 ][ u ]表示在 i 这棵子树中选择 u 个且 i 不用优惠券的最小花费。
dp[ i ][ 1 ][ u ]表示在 i 这棵子树中选择 u 个且 i 用优惠券的最小花费。
注意这个转移总的合起来是O(n ^ 2)的。
#include<bits/stdc++.h> #define LL long long #define fi first #define se second #define mk make_pair #define PLL pair<LL, LL> #define PLI pair<LL, int> #define PII pair<int, int> #define SZ(x) ((int)x.size()) #define ull unsigned long long using namespace std; const int N = 5000 + 7; const int inf = 0x3f3f3f3f; const LL INF = 0x3f3f3f3f3f3f3f3f; const int mod = 1e9 + 7; const double eps = 1e-8; int n, b, d[N], c[N], fa[N]; vector<int> G[N]; int dp[N][2][N]; int tmp[N][2][N]; int sum[N]; void dfs(int u) { sum[u] = 1; memset(dp[u], inf, sizeof(dp[u])); dp[u][0][0] = 0; dp[u][0][1] = c[u]; dp[u][1][1] = c[u] - d[u]; for(auto& v : G[u]) { dfs(v); memset(tmp[u], INF, sizeof(tmp[u])); for(int i = 0; i <= sum[u]; i++) { for(int j = 0; j <= sum[v]; j++) { tmp[u][0][i + j] = min(tmp[u][0][i + j], dp[u][0][i] + dp[v][0][j]); tmp[u][1][i + j] = min(tmp[u][1][i + j], dp[u][1][i] + dp[v][0][j]); tmp[u][1][i + j] = min(tmp[u][1][i + j], dp[u][1][i] + dp[v][1][j]); } } sum[u] += sum[v]; memcpy(dp[u], tmp[u], sizeof(dp[u])); } } int main() { scanf("%d%d", &n, &b); for(int i = 1; i <= n; i++) { scanf("%d%d", &c[i], &d[i]); if(i > 1) { scanf("%d", &fa[i]); G[fa[i]].push_back(i); } } dfs(1); for(int i = n; i >= 0; i--) { if(dp[1][0][i] <= b || dp[1][1][i] <= b) { printf("%d\n", i); return 0; } } return 0; } /* */