附图:
题目大意:
你要去商店买东西,每个东西有一个价格
c
i
c_i
c i 和一个折扣
d
i
d_i
d i ,你可以享受到物品
d
i
d_i
d i 的折扣当且仅当你之前买了物品
x
i
x_i
x i ,并且享受到了物品
x
i
x_i
x i 的折扣。保证除第一个点之外,每个点都只有一个
x
i
x_i
x i (第一个点没有
x
i
x_i
x i )。你有
m
m
m 元钱,求你最多能买多少东西。
由题意得,折扣关系是一棵树,享受这个点的折扣的条件是买它的父亲,并且父亲也享受折扣,因此也要买父亲的父亲,父亲的父亲也享受折扣……因此,享受一个点折扣最终的条件就是这个点的祖先全部都买。
这样也就形成了一个依赖关系,我们定义数组
f
[
i
]
[
j
]
f[i][j]
f [ i ] [ j ] 表示点
i
i
i ,它的子树(包括自己)买了
j
j
j 个点,且购买点
i
i
i 时享受到了折扣的最小费用;
g
[
i
]
[
j
]
g[i][j]
g [ i ] [ j ] 表示点
i
i
i ,它的子树里买了
j
j
j 个点,并且所有的点都不享受折扣的最小费用。那么进行背包处理,即可得出转移的方程式:
g[x][0]=0;f[x][1]=v[x]-dc[x];g[x][1]=v[x];siz[x]=1;
for(i=siz[x];i>=0;i--)
for(j=1;j<=siz[to];j++)
g[x][i+j]=min(g[x][i+j],g[x][i]+g[to][j]);
for(i=siz[x];i>=1;i--)
for(j=1;j<=siz[to];j++)
f[x][i+j]=min(f[x][i+j],f[x][i]+min(f[to][j],g[to][j]));
这个方程式可以这样理解,对于上面那个
g
g
g 数组,相当于就是一个分组背包,每个子树可以看成一个组,组里只能选一种情况。
而
f
f
f 数组也是同理,只是由于
i
i
i 点必须享受到折扣,所以
i
i
i 点必选,那么枚举
s
i
z
e
size
s i z e 的时候只枚举到
1
1
1 即可。
这里还有一个操作,就是
s
i
z
[
x
]
siz[x]
s i z [ x ] 先处理后加,这样做能极大地优化时间复杂度。
#include<bits/stdc++.h>
#define MAXN 5005
#define ll long long
using namespace std;
ll read(){
char c;ll x;while(c=getchar(),c<'0'||c>'9');x=c-'0';
while(c=getchar(),c>='0'&&c<='9') x=x*10+c-'0';return x;
}
ll n,m,ans,flag,v[MAXN],dc[MAXN],f[MAXN][MAXN],g[MAXN][MAXN];
ll cnt,head[MAXN<<1],nxt[MAXN<<1],go[MAXN<<1],siz[MAXN];
void add(ll x,ll y){
go[cnt]=y;nxt[cnt]=head[x];head[x]=cnt;cnt++;
}
void dfs(ll x){
register int i,j,k;
g[x][0]=0;f[x][1]=v[x]-dc[x];g[x][1]=v[x];siz[x]=1;
for(k=head[x];k!=-1;k=nxt[k]){
ll to=go[k];dfs(to);
for(i=siz[x];i>=0;i--)
for(j=1;j<=siz[to];j++)
g[x][i+j]=min(g[x][i+j],g[x][i]+g[to][j]);
for(i=siz[x];i>=1;i--)
for(j=1;j<=siz[to];j++)
f[x][i+j]=min(f[x][i+j],f[x][i]+min(f[to][j],g[to][j]));
siz[x]+=siz[to];
}
}
int main()
{
n=read();m=read();register int i;
memset(head,-1,sizeof(head));
memset(f,127,sizeof(f));
memset(g,127,sizeof(g));
for(i=1;i<=n;i++){
v[i]=read();dc[i]=read();
if(i>1){ll x=read();add(x,i);}
}
dfs(1);
for(i=n;i;i--)
if(f[1][i]<=m||g[1][i]<=m){flag=1;printf("%d",i);break;}
if(!flag) puts("0");
return 0;
}