[机房测试]购物
Description
\(n\) 个物品,价值为 \(a_i\),使用优惠券会便宜 \(d_i\),优惠券使用限制构成树形关系,必须父亲使用了优惠券,当前点才能使用。现有 \(b\leq 10^9\) 元钱,求最多能买多少个物品。
Solution
MLE了,唱歌。
不能将费用计入状态,所以可以考虑反过来将个数计入状态。\(dp_{u,j,0/1}\) 表示以 \(u\) 为根的子树中,选了 \(j\) 个数,\(u\) 使不使用优惠券的最小花费。那么显然有转移
\[dp_{u,0,0}=0\\
dp_{u,1,0}=a_u\\
dp_{u,1,1}=a_u-d_u\\
dp_{u,j+k,0}=\min\{dp_{u,j,0}+dp_{v,k,0}|j\in [0,sz_u]\}\\
dp_{u,j+k,1}=\min\{dp_{u,j,1}+\min\{dp_{v,k,0},dp_{v,k,1}\}|j\in [1,sz_u]\}
\]
#include<stdio.h>
#include<vector>
#include<algorithm>
using namespace std;
inline int read(){
int x=0,flag=1; char c=getchar();
while(c<'0'||c>'9'){if(c=='-')flag=0;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-48;c=getchar();}
return flag? x:-x;
}
const int N=5e3+7;
int sz[N],c[N],d[N];
vector<int> G[N];
int dp[N][N][2];
inline void Min(int &x,int y){x=min(x,y);}
void dfs(int u){
sz[u]=1;
dp[u][0][0]=0;
dp[u][1][0]=c[u];
dp[u][1][1]=c[u]-d[u];
for(int v:G[u]){
dfs(v);
for(int j=sz[u];~j;j--)
for(int k=sz[v];k;k--){
if(j) Min(dp[u][j+k][1],dp[u][j][1]+min(dp[v][k][0],dp[v][k][1]));
Min(dp[u][j+k][0],dp[u][j][0]+dp[v][k][0]);
}
sz[u]+=sz[v];
}
}
int main(){
freopen("shopping.in","r",stdin);
freopen("shopping.out","w",stdout);
int n=read(),b=read();
for(int i=1;i<=n;i++){
c[i]=read(),d[i]=read();
if(i>=2) G[read()].push_back(i);
}
for(int i=0;i<=n;i++)
for(int j=0;j<=n;j++)
dp[i][j][0]=dp[i][j][1]=b+1;
dfs(1);
for(int i=n;~i;i--)
if(min(dp[1][i][0],dp[1][i][1])<=b) return printf("%d",i),(0-0);
}