首页 > 代码库 > 多重背包

多重背包

【问题描述】

        有N种物品和一个容量为w的背包,第i种物品最多有m[i]件可用,每件容量是c[i],价值是v[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。

【输入】

          第一行 正整数n和w

         以下n行,每行三个正整数为物品的容量、价值和件数,中间用空格隔开。

【输出】

最大价值总和。

【数据规模】

        1<= n<=100, w<=10000, 1<=m[i]<=10000, 1<=c[i],v[i]<=100

 分析:

方法1,朴素算法:f[i,j]表示前i种物品装入容量为j的背包中所能得到的最大价值(0<=k<=min(m[i],j div v[i]))。  

         f[i,j]=max{f[i-1,j-k*c[i]]+k*v[i]}   ,0<=k<=min(m[i],j div v[i])。   

         时间复杂度O(n*V*∑m[i])

方法2,转换为01背包,利用二进制拆分

          假设第i种物品有m[i]件,则可以第i种物品看成m[i]件01背包中的物品,则得到了物品数为Σm[i]的01背包问题,直接求解.时间复杂度:O(V*Σ m[i])。

二进制拆分:

       m[i]=1+2+4+...+2^k+a   (0<=a<2(k+1),a=n-2^(K+1)+1)

       由于1,2....,2^k可以表示0~2^(K+1)-1中的所有整数(由K位二进制表示),则1,2,4,...,2^k,a可以表示出0~m[i]的所有整数(a与0~2^(K+1)-1的所有整数相加,可以表示出2^(K+1)~n的所有整数)。

       m[i]可以分解出log(m[i])+1个背包,则时间复杂度为O(V*∑log(m[i]))

方法3,单调队列

    方法1中f[i,j]=max{f[i-1,j-k*c[i]]+k*v[i]}   ,0<=k<=min(m[i],j div v[i])。

   令a[j]=f[i-1,j*c[i]],k=min(m[i],j div v[i]则有

   f[i,(j+k)*c[i]]=max{f[i-1,(j+k)*c[i]-k*c[i]]+k*v[i],f[i-1,(j+k)*c[i]-(k-1)*c[i]]+(k-1)*c[i],...,f[i-1,(j+k)*c[i]+(k-k)*c[i]]+(k-k)*c[i] 

                       =max{f[i-1,j*c[i]]+k*v[i],f[i-1,(j+1)*c[i]]+(k-1)*c[i],...f[i-1,(j+k)*c[i]]}

                       =max{a[j]+k*c[i],a[j+1]+(k-1)*c[i],...,a[j+k]}

这样还是不方便计算,令b[j]=a[j]-j*c[i]

    则有f[i,(j+k)*c[i]]=max{b[j]+(j+k)*c[i],b[j+1]+(J+K)*c[i],...,b[j+k]+(j+k)*c[i]}

                               =max{b[j],b[j+1],...,b[j+k]}+(j+k)*c[i]

这样就可以使用单调队列来求解了。时间复杂度O(nV)