Description
Input
Output
Sample Input
6 9
1 1 1
1 1 100
8 1 1
1 3 6
2 3 1000
4 1 4
Sample Output
105
【样例解释】
其中一种最优解为:小C用 8 点能量摘下第 1,2,4,6 朵花,并放在药材中熬煮,由于第 4 朵花所钦慕的 3 号花不在药材中,所以第 4 朵花渐渐枯萎消失。最后剩下 3 朵花:1,2,6,药材所获得的最大贡献为 1+100+4=105。
Data Constraint
思路
其实就是一个树上01背包。
首先求出这棵树的dfs序,设lx表示以x为根的子树中的dfs序最小值(即点rx的dfs序),设rx表示以x为根的子树中的dfs序最大值。
然后按照dfs序枚举点,每个点维护一个背包,对于点x,如果选这个点,就把它加到lx + 1的背包里,如果不选这个点,就把点x的背包与rx + 1的背包合并
这样,不管这个点选或不选,都是O(m)的时间复杂度,所以总的复杂度是
O(nm)。
代码
#include<iostream>
#include<cstdio>
#define maxn 5007
using namespace std;
int v[maxn],w[maxn],list[maxn],size[maxn],dfn[maxn],f[maxn][10003],n,p,cnt=0;
struct node
{
int u,next;
}g[maxn];
void dfs(int x)
{
dfn[++cnt]=x;
size[x]=1;
for (int i=list[x]; i>0; i=g[i].next)
{
dfs(g[i].u);
size[x]+=size[g[i].u];
}
}
int main()
{
freopen("medicine.in","r",stdin);
freopen("medicine.out","w",stdout);
scanf("%d%d",&n,&p);
for (int i=1; i<=n; i++)
{
int t;
scanf("%d%d%d",&w[i],&t,&v[i]);
if (i!=1)
{
g[i].u=i; g[i].next=list[t]; list[t]=i;
}
}
dfs(1);
for (int i=n; i>=1; i--)
{
int k=dfn[i];
for(int j=0; j<=p; j++) f[i][j]=max(f[i+size[k]][j],0);
for(int j=w[k]; j<=p; j++) f[i][j]=max(f[i][j],f[i+1][j-w[k]]+v[k]);
}
int ans=0;
for(int i=0; i<=p; i++) ans=max(ans,f[1][i]);
printf("%d",ans);
}