zoukankan      html  css  js  c++  java
  • [经典] 背包问题(一)

    【1】01背包

    N个物品,占容c[i],价值w[i],放入1个容量为V的背包,使得总价值最大

    分析:每种物品仅有一件,可以选择放或不放

    转移方程:opt[i][v] = max{opt[i - 1][v], opt[i - 1][v - c[i]] + w[i]}

    复杂度:时间空间均为O(NV),空间复杂度可压缩,用opt[v]表示,但需要注意的是v必须从V到0遍历,否则逻辑错误;

    初始化技巧:如果要求刚好装满,则设为负无穷;如果只要求最大,则设为0即可。

    事实上,由于对某件物品的01处理问题会在不同情景下都被调用,所以可以写成一个调用函数ZeroOnePack(cost, weigth),其中v的下限可被优化

    procedure ZeroOnePack(cost,weight)     
        for v=V..cost 
            f[v]=max{f[v],f[v-cost]+weight} 

    所以本题的伪代码可以写成

    for i=1..N 
        ZeroOnePack(c[i],w[i]);

    另外,其实下限可以进一步被优化,当V很大时有效,此时本题的伪代码可以写成

    for i=1..n 
        bound=max{V-sum{w[i..n]},c[i]}     
        for v=V..bound     
       f[v]=max{f[v],f[v-cost]+weight} 

    【2】完全背包

    特点是每件物品的数目都是没有限制的,可以由01背包延展出解法,即f[i][v]=max{f[i-1][v-k*c[i]]+k*w[i]}, 0<=k*c[i]<=v;复杂度很显然上升了O(v/c[i]),所以尝试找到优化的方法。最简单的优化:c[i] < c[j] && w[i] > w[j],则显然应该选择w[i],去除j物品。

    先是最小均分,将每个物品当成有v/c[i]个,则完全背包等效于01背包,复杂度仍比01上升O(v/c[i]);然后是指数拆分,将每个物品拆分成费用为c[i]*2^k、价值为w[i]*2^k的子物品,则复杂度只上升O(log(v/c[i]))。

    经典解法:复杂度与01背包一样,只有O(VN)。动态规划方程为f[i][v]=max{f[i-1][v],f[i][v-c[i]]+w[i]},而空间复杂度为O(V)的算法只需要将v从0到V顺序遍历。

    procedure CompletePack(cost,weight)     
        for v=cost..V 
            f[v]=max{f[v],f[v-c[i]]+w[i]}

    事实上,v循环与i循环的次序可以颠倒

    【3】多重背包

    特点是每件物品的数目有中庸的限制,即第i件物品的数目限制是n[i]。最直接的方法也是拆分01背包,f[i][v]=max{f[i-1][v-k*c[i]]+k*w[i]}, 0<=k<=n[i],复杂度为O(V*Σn[i]);然后是指数拆分,也是经典解法,复杂度为O(V*Σlog n[i])。

    procedure MultiplePack(cost,weight,amount)     
        if cost*amount>=V 
            CompletePack(cost,weight)         
            return     
        integer k=1     
        while k<amount 
            ZeroOnePack(k*cost,k*weight)         
            amount=amount-k        
            k=k*2 
            ZeroOnePack(amount*cost,amount*weight)

    还有复杂度更低的方法,复杂度与01背包一样,只有O(VN),方法是单调队列优化,超了NOIP范围。

    【4】混合背包

    将前三种背包过程分类混合使用,伪代码:

    for i=1..N 
        if 第i件物品属于01背包        
            ZeroOnePack(c[i],w[i])     
        else if 第i件物品属于完全
            CompletePack(c[i],w[i])    
        else if 第i件物品属于多重背包         
            MultiplePack(c[i],w[i],n[i])         

    【5】二维费用背包

    多用一个状态记录多出来的费用,设f[i][v][u]表示前i件物品付出两种代价分别为v和u时可获得的最大价值。状态转移方程就是: 

    f[i][v][u]=max{f[i-1][v][u],f[i-1][v-a[i]][u-b[i]]+w[i]} 
  • 相关阅读:
    asp.net调用mysql 存储过程 带 out 返回值,返回刚插入数据库中的自增的ID,LAST_INSERT_ID() 的使用
    如何俘获一个 IT 男的心,让他成为男友然后变成老公?
    MySqlHelper.cs mysql数据库助手类
    mysql 按年度、季度、月度、周、日SQL统计查询,mysql 存储过程 中 in 和 FIND_IN_SET 传递多个参数的使用
    奇怪的母版页里面的 form 表单里面的 enctype="multipart/formdata" html控件上传 FileUpload控件上传 一次多图片上传
    asp.net 连接 Mysql 代码生成器(下载地址)
    Convert.ToInt32、(int)和int.Parse,int.TryParse四者之间的区别:
    在web项目中 使用 WebService 根据IP地址来源搜索实际物理地址,常用的WebServices
    vc6控制台程序利用SoapToolkit3.0调用WebService
    浅议C++/CLI的gcnew关键字
  • 原文地址:https://www.cnblogs.com/littletail/p/5413242.html
Copyright © 2011-2022 走看看