单调队列优化和二进制优化的多重背包模板

多重背包

F[i][j]表示对容量为j的背包,处理完前i种物品后,背包内物品可达到的最大总价值。

num[i]表示第i种物品的数量,cost[i]表示第i种物品的花费,value[i]表示第i种物品的价值。

mi[i] = min(num[i], j / cost[i])

放入背包的第i种物品的数目可以是:0、1、2……,可得转移方程:

  F[i][j] = max { F[i - 1] [j – k * cost[i] ] + k * value[i] }  (0 <= k <= mi[i]) 

上面的式子就是朴素的多重背包转移方程式。

二进制优化

二进制优化是基于对于每一种物品的数量分成件数为1,2,4,8……的多个物品

一种物品可以分为logn件不同的物品

然后就等同于01背包的问题

复杂度:O(n*m*logn)

单调队列优化

假设 a = j / cost[i],b = j % cost[i],即 j = a * cost[i] + b

代入朴素的转移方程式,并用k替换a - k得:

F[i][j] = max { F[i - 1] [b + k * cost[i]] - k * value[i] } + a * value[i]  

(a – mi[i] <= k <= a) 很重要的判断,用于去除队首的无效值

单调队列维护队首的max F[i - 1] [b + k * cost[i]] - k * value[i]

从对位添加F[i - 1] [b + k * cost[i]] - k * value[i]时,若大于队尾,则删除队尾

复杂度:O(n*m)

for(int i=1;i<=n;i++)
    {
        for(int j=0;j<cost[i];j++)
        {
            q[head=tail=1]=make_pair(f[j],0);
            for(int k=j+cost[i];k<=m;k+=cost[i])
            {
                int a=k/cost[i],t=f[k]-a*value[i];
                while(head<=tail&&q[tail].first<=t)tail--;
                q[++tail]=make_pair(t,a);
                while(head<=tail&&q[head].second+num[i]<a)head++;
                f[k]=max(f[k],q[head].first+a*value[i]);
            }
        }
    }
View Code

 

posted on 2018-08-24 16:30  solvit  阅读(317)  评论(0)    收藏  举报

导航