zoukankan      html  css  js  c++  java
  • p1915//背包小结

    一道经典的有依赖的背包问题.

    我们先从01背包说起.有一群物品给定了重量w和收入v,问在一定资金下最大的收入是多少.作为一道经典的背包大家应该都会,o[i]表示i块钱时的最大收入,每个物品都可以使价格i从o[i-w]转移过来,即o[i]=max(o[i],o[i-w]+v);所以读入每个物品的时候可以循环一遍o用来更新.复杂度是nv;

    然后说分组背包.有k组物品,每个组内的物品只能用一个,这个时候我们需要二维数组o[i][f]表示第i组花f块钱时的最大收入.对于每个物品还是可以使第i组价格f从o[i-1][f-w]转移过来,即o[i][f]=max(o[i][f],o[i-1][f-w]+v);

    对于有依赖的背包问题,我们可以枚举每个物品选与不选的2^n-1种情况组成2^n-1个物品,这些物品两两间是不能同时取的.由于有多个游戏机,本题应该先用二进制模拟预处理出2^n-1个物品后用分组背包.

    但是!这样写是会超时的.50*1024*100000=超时.会少很多很多分.

    这个时候怎么办呢?继续分组应该是不行的,因为100000一定会出现在表达式中,一旦乘1024就会超时,更不要说那个50和调用函数的时间了(分组我写的是一个dfs...)那么改怎么做呢?

    我们考虑为什么不能用01背包继续做这个题?因为游戏机本身需要钱.因为不能确定应该用w转移还是w+gp_j转移,假如这个点没有被本组内物品更新过是应该加上pg_j的,否则就不应该加.所以所以会出现这样的情况.

    好像一筹莫展了?为什么不直接把上一组的答案加上gp_j后再来做01呢?不是等价的么?

    for(i=v;i<=sum;i++)
        O[i]=o[i-v];
    for(i=1;i<=n;i++)
    {
        tv=read();tw=read();
        for(f=sum;f>=tv+v;f--)
            O[f]=max(O[f],O[f-tv]+tw);
    }
    for(i=0;i<=sum;i++)
        o[i]=max(o[i],O[i]);

    本题结束,就这几行的内容最重要.

    using namespace std;
    int i,f;
    int n,v,tv,tw,sum,T;
    int O[100010],o[100010];
    int main()
    {
        T=read();sum=read();
        for(;T;T--)
        {
            v=read();n=read();
            for(i=v;i<=sum;i++)
                O[i]=o[i-v];
            for(i=1;i<=n;i++)
            {
                tv=read();tw=read();
                for(f=sum;f>=tv+v;f--)
                    O[f]=max(O[f],O[f-tv]+tw);
            }
            for(i=0;i<=sum;i++)
                o[i]=max(o[i],O[i]);
        }
        for(i=1;i<=sum;i++)
            o[0]=max(o[0],o[i]);
        write(o[0]);
    }
  • 相关阅读:
    eclipse新建maven web项目
    mongodb启用Profiling定位问题
    Linux下系统监控工具nmon使用
    MMS(mongodb监控工具)
    Linux下定时切割Mongodb数据库日志并删除指定天数前的日志记录
    mongodb sharding集群搭建
    linux 下mongodb 3.2.5单机版安装
    linux mongodb replica set集群安装
    DOS命令查询当前文件夹中文件数量
    centos7 开放mongodb端口
  • 原文地址:https://www.cnblogs.com/qywyt/p/9833145.html
Copyright © 2011-2022 走看看