【codevs1155】金明的预算方案

开始我的想法是对于加了附件的物品当成新的做,结果发现好像并不行啊,会有重复计算的存在

所以直接01背包是不行了,然后我看到网上的题解,有两种方法,一种是分组背包(看起来处理好麻烦qwq),还有种是树形背包,正好没学过2333333,来愉快的学一下

这个题如果用树形背包来做的话,是把主件当成根节点,建一棵树,因此就避免了重复计算,但是如果只是这样会形成森林,因此我们把0作为所有主件的根节点

#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;
struct in
{
    int fr,to,ne;
}ter[120];
int n,m,tail,v[65],p[65],x,y,z,dp[65][32010],head[120];
inline void build(int f,int l)//建出一棵树来,把附件挂在树上,这样就可以避免01背包重复使用的乱七八糟的问题了 
{
    ter[++tail]=(in){f,l,head[f]},head[f]=tail;
}
void dfs(int no,int w)
{
    if(w<=0)
        return;
    for(int i=head[no];i>0;i=ter[i].ne)
    {
        int t=ter[i].to;
        for(int j=0;j<=w-v[t];j++)//先初始化子树的根节点 
            dp[t][j]=dp[no][j];//以前取好的物品一定取 
        dfs(t,w-v[t]);//继续往下面找 
        for(int j=v[t];j<=w;j++)//然后用下面的选取方案来更新上层 
            dp[no][j]=max(dp[no][j],dp[t][j-v[t]]+p[t]);
    }
}
int main()
{
    memset(head,-1,sizeof(head));
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
        scanf("%d%d%d",&x,&y,&z),v[i]=x,p[i]=x*y,build(z,i);
    dfs(0,n);
    printf("%d",dp[0][n]);
}

 

posted @ 2017-10-23 09:11  那一抹落日的橙  阅读(173)  评论(0编辑  收藏  举报