题目链接:Codeforces - Karen and Supermarket
每一个优惠券之间构成了一颗树,要子节点能优惠,就必须选父亲节点优惠。
很明显是一个树上背包。直接做即可。
dp[i][j][0/1]代表i节点选j个,是否用优惠券。
AC代码:
#pragma GCC optimize("-Ofast","-funroll-all-loops")
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=5e3+10;
int n,b,c[N],d[N],dp[N][N][2],sz[N];
vector<int> g[N];
void dfs(int x){
sz[x]=1;
dp[x][0][0]=0,dp[x][1][0]=c[x],dp[x][1][1]=c[x]-d[x];
for(auto to:g[x]){
dfs(to);
for(int i=sz[x];i>=0;i--){
for(int j=0;j<=sz[to];j++) if(i+j<=n){
dp[x][i+j][1]=min(dp[x][i+j][1],dp[x][i][1]+dp[to][j][1]);
dp[x][i+j][1]=min(dp[x][i+j][1],dp[x][i][1]+dp[to][j][0]);
dp[x][i+j][0]=min(dp[x][i+j][0],dp[x][i][0]+dp[to][j][0]);
}
}
sz[x]+=sz[to];
}
}
signed main(){
cin>>n>>b>>c[1]>>d[1]; memset(dp,0x3f,sizeof dp);
for(int i=2,x;i<=n;i++){
cin>>c[i]>>d[i]>>x; g[x].push_back(i);
}
dfs(1);
for(int i=n;i>=1;i--) if(dp[1][i][1]<=b||dp[1][i][0]<=b){
return cout<<i,0;
}
cout<<0;
return 0;
}