[经典] 背包问题(一)

【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]} 

 

posted @ 2016-04-25 13:53  CarlGoodman  阅读(529)  评论(0编辑  收藏  举报