dp训练第22题 luoguP1064 金明的预算方案 依赖背包

6人阅读 评论(2) 收藏 举报
分类:

给定背包容量v(32000),物品个数n(60),每个物品有三个参数volume[i],(value[i]/volume[i]),fa[i],其中fa[i]为0时表示该物品是主件,不为0时表示是附件且fa[i]就是它的主件编号.
其中,每个物品最多被两件物品所依赖.

这是一个简化后的问题,只要对每个主件的附件集合求一个01背包,复杂度O(V^2*n)
但是注意到v有32000,而且每个主件只会被最多两个物品依赖,每个主件集合最多只会有五种状态(相当于四个物品).依次枚举更好,复杂度O(n*V)

代码

wa一次,因为第一次写的时候没有分组.
注意不管是泛化物品还是二进制枚举依赖物品,一定是分成互斥物品组的.
遍历顺序是 先遍历组-再遍历体积-再遍历组中物品.

关于二进制枚举,我使用了掩码mask的方式,套路如下:

for(int mask=0;mask<(1<<px);mask++)
{
    for(int pm=0;pm<px;pm++)
        if(mask&(1<<pm))
            //add it
    //do something
}

其中px是要枚举的基数个数,多做几道状压dp就熟练了.

/* LittleFall : Hello! */
#include <bits/stdc++.h>
#define ll long long
using namespace std;
inline int read();
inline void write(int x);
const int N = 128,V=32768;
struct Item
{
    int fa;
    int volume;
    int value;
    vector<pair<int,int>> sons;
    bool operator<(const Item &b) const
    {
        return fa<b.fa;
    }
}save[N];
int dp[V];
int main(void)
{
    #ifdef _LITTLEFALL_
    freopen("in.txt","r",stdin);
    #endif
    //std::cin.sync_with_stdio(false); 

    int v=read(),xn=read(),n=0;
    for(int i=1;i<=xn;i++)
    {
        save[i].volume=read();
        save[i].value=save[i].volume*read();
        save[i].fa=read();
        if(!save[i].fa) n++;
        else 
            save[save[i].fa].sons.
                emplace_back(save[i].volume,save[i].value);
    }
    sort(save+1,save+xn+1);

    for(int i=1;i<=n;i++)
    {
        int px=save[i].sons.size();
        for(int j=v;j>=0;j--)
            for(int mask=0;mask<(1<<px);mask++)
            {
                int volu=save[i].volume,valu=save[i].value;
                for(int pm=0;pm<px;pm++)
                    if(mask&(1<<pm))
                        volu+=save[i].sons[pm].first,valu+=save[i].sons[pm].second;     
                if(volu<=j)
                    dp[j]=max(dp[j],dp[j-volu]+valu);
            }
    }
    printf("%d\n",dp[v] );

    return 0;
}


inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9') {if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
inline void write(int x)
{
     if(x<0) putchar('-'),x=-x;
     if(x>9) write(x/10);
     putchar(x%10+'0');
}

4月17日加:
使用真正的依赖背包法做一下:

/* LittleFall : Hello! */
#include <bits/stdc++.h>
#define ll long long
using namespace std;
inline int read();
inline void write(int x);
const int N = 64, V = 32768;
int dp[V],tmp[V];
struct Item
{
    int volume;
    int value;
    int fa;
    vector<pair<int,int>> sons;
    bool operator<(const Item & b) const
    {
        return fa<b.fa;
    }
}save[N];

int main(void)
{
    #ifdef _LITTLEFALL_
    freopen("in.txt","r",stdin);
    #endif
    //std::cin.sync_with_stdio(false); 

    int v=read(),xn=read(),n=xn;
    for(int i=1;i<=xn;i++)
    {
        save[i].volume=read();
        save[i].value=save[i].volume*read();
        save[i].fa=read();
        if(save[i].fa)
        {
            n--;
            save[save[i].fa].sons.push_back(
                {save[i].volume,save[i].value});
        }
    }
    sort(save+1,save+xn+1);

    for(int i=1;i<=n;i++)
    {
        memcpy(tmp,dp,sizeof(dp));
        for(int k=save[i].sons.size()-1;k>=0;k--)
        {
            int volu=save[i].sons[k].first,valu=save[i].sons[k].second;
            for(int j=v;j>=volu;j--)
                tmp[j]=max(tmp[j],tmp[j-volu]+valu);
        }
        for(int j=v;j>=save[i].volume;j--)
            dp[j]=max(dp[j],tmp[j-save[i].volume]+save[i].value);
    }
    printf("%d\n",dp[v] );

    return 0;
}


inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9') {if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
inline void write(int x)
{
     if(x<0) putchar('-'),x=-x;
     if(x>9) write(x/10);
     putchar(x%10+'0');
}

速度约比上一版快了3倍,而且没有物品数限制.

查看评论

有依赖的01背包问题( 金明的预算方案)

转载至:http://blog.csdn.net/liang5630/article/details/8030108 考虑到每个主件最多只有两个附件,因此我们可以通过转化,把原问题转化为01...
  • qiweizhihong
  • qiweizhihong
  • 2017-07-10 10:46:11
  • 229

蓝桥杯 算法提高 金明的预算方案 有依赖的背包问题

算法提高 金明的预算方案   时间限制:1.0s   内存限制:256.0MB      问题描述   金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间金明自己...
  • lxy767087094
  • lxy767087094
  • 2017-02-18 13:19:28
  • 228

【Algothrim】 动态规划实例 (金明的预算方案 )

Description 金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间金明自己专用的很宽敞的房间。更让他高兴的是,妈妈昨天对他说:“你的房间需要购买哪些物品,怎么布置,你说了算,只要不超...
  • carol123456
  • carol123456
  • 2016-08-18 19:21:48
  • 2594

算法提高 金明的预算方案

算法提高 金明的预算方案   时间限制:1.0s   内存限制:256.0MB      问题描述   金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间金明自己专用的很宽敞的房间。...
  • Go_Accepted
  • Go_Accepted
  • 2017-02-22 17:42:27
  • 2301

【NOIP2006】金明的预算方案

题面【问题描述】金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间金明自己专用的很宽敞的房间。更让他高兴的是,妈妈昨天对他说:“你的房间需要购买哪些物品,怎么布置,你说了算,只要不超过N元钱就行...
  • qq_22141519
  • qq_22141519
  • 2015-08-01 15:42:34
  • 1650

蓝桥杯_算法提高_金明的预算方案(动态规划、01背包变形)

问题描述   金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间金明自己专用的很宽敞的房间。更让他高兴的是,妈妈昨天对他说:“你的房间需要购买哪些物品,怎么布置,你说了算,只要不超过N元钱就行...
  • huangxiang360729
  • huangxiang360729
  • 2016-03-31 22:27:23
  • 724

NOIP 2006 金明的预算方案 (裸?)分组背包

或许还有其他方式,不过我就是按分组背包写的,几近裸题。 我也是纳闷,前两天刚刚做过一道分组背包的题,理解了分组背包的正确打开方式,今天却差点没想出来。真是。。。该去睡一会。对于每个物品以及它的附件,...
  • qq_25978793
  • qq_25978793
  • 2015-09-19 15:47:42
  • 311

【NOIP2006提高组】金明的预算

【问题描述】         金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间金明自己专用的很宽敞的房间。更让他高兴的是,妈妈昨天对他说:“你的房间需要购买哪些物品,怎么布置,你...
  • cqyz_yuyuko
  • cqyz_yuyuko
  • 2016-08-04 22:17:49
  • 227

[动态规划] 洛谷P1064 金明的预算方案

洛谷P1064 金明的预算方案 树形DP... 但是可以用背包做呢 一维四状态的背包
  • qq_36038511
  • qq_36038511
  • 2017-04-28 14:09:38
  • 633

codevs 1155 金明的预算方案——来自深夜的挫败- -

codevs 1155 金明的预算方案——来自深夜的挫败- - 没想到到了今天的最后时刻我还是没把这题做出来。最开始以为可能有3个附件,觉得自己枚举6种组合,代码太冗余了,就不想这么写。于是乎去写了...
  • qq_33826977
  • qq_33826977
  • 2017-03-09 00:06:32
  • 171
    个人资料
    持之以恒
    等级:
    访问量: 6451
    积分: 1331
    排名: 3万+
    文章存档
    最新评论