【GDOI2018Day1模拟4.17】药香沁鼻

Description

0=w=0

Input

FAQ

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);
}

猜你喜欢

转载自blog.csdn.net/eric1561759334/article/details/80011424
今日推荐