[jzoj 5661] 药香沁鼻 解题报告 (DP+dfs序)

Posted xxzh

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[jzoj 5661] 药香沁鼻 解题报告 (DP+dfs序)相关的知识,希望对你有一定的参考价值。

interlinkage:

https://jzoj.net/senior/#contest/show/2703/0

description:

技术图片

solution:

  • 注意到这本质就是一个背包,只是选了一个点就必须把它到根节点的所有的点都选上
  • 考虑如何转移这个背包,发现一个点要么转移到$dfs$序比它大$1$的点上,要么转移到比这个点子树中$dfs$序最大的点的$dfs$序大$1$的点上
  • 前者表示这条链继续选,后者表示放弃这条链
  • 易得所有的状态都会被转移到
  • 这是一个很经典的问题

code:

#include<algorithm>
#include<cstring>
#include<iostream>
#include<cstdio>
using namespace std;

const int N=5e3+15;
const int M=1e4+15;
int n,p,ans,tot,tim;
int w[N],f[N],v[N],head[N],dp[N][M],id[N],st[N],ed[N];
struct EDGE
{
    int to,nxt;
}edge[N<<1];
inline int read()
{
    char ch=getchar();int s=0,f=1;
    while (ch<0||ch>9) {if (ch==-) f=-1;ch=getchar();}
    while (ch>=0&&ch<=9) {s=(s<<3)+(s<<1)+ch-0;ch=getchar();}
    return s*f;
}
void add(int u,int v)
{
    edge[++tot]=(EDGE){v,head[u]};
    head[u]=tot;
}
void dfs(int x)
{
    st[x]=++tim;id[tim]=x;
    for (int i=head[x];i;i=edge[i].nxt)
        dfs(edge[i].to);
    ed[x]=tim;
}
int main()
{
    freopen("medicine.in","r",stdin);
    freopen("medicine.out","w",stdout);
    n=read();p=read();
    w[1]=read();f[1]=read();v[1]=read();
    for (int i=2;i<=n;i++)
    {
        w[i]=read();f[i]=read();v[i]=read();
        add(f[i],i);
    }
    dfs(1);
    memset(dp,-0x3f,sizeof(dp));
    dp[1][0]=0;
    for (int i=1;i<=tim;i++)
    {
        int x=id[i];
        for (int j=0;j<=p;j++) if (dp[i][j]>=0)
        {
            if (j+w[x]<=p) dp[i+1][j+w[x]]=max(dp[i+1][j+w[x]],dp[i][j]+v[x]);
            dp[ed[x]+1][j]=max(dp[ed[x]+1][j],dp[i][j]);
            ans=max(ans,dp[i][j]);
        }
    }
    for (int i=0;i<=p;i++) ans=max(ans,dp[tim+1][i]);
    printf("%d
",ans);
    return 0;
}

以上是关于[jzoj 5661] 药香沁鼻 解题报告 (DP+dfs序)的主要内容,如果未能解决你的问题,请参考以下文章

jzoj1495 宝石 解题报告[扫描线]

[JZOJ4024] [佛山市选2015] 石子游戏 解题报告

[jzoj 6084] [GDOI2019模拟2019.3.25] 礼物 [luogu 4916] 魔力环 解题报告(莫比乌斯反演+生成函数)

JZOJ 养猪 (dp-01背包)

jzoj1340状压DP周长

Jzoj 3056NOIP2012模拟10.27容斥DP数学数字