经典问题之多重背包的总结与提升

来源:互联网 发布:同花顺中天软件下载 编辑:程序博客网 时间:2024/06/05 04:12

多重背包:

1.基础题型

伪代码:

   i=1 to n

    j=1 to W

     k=1 to m[i]

      f[j]=max{f[j-k*w[i]]+k*v[i]}


2.加强版

(一)对于数据不是特别紧的可采用二进制法,效率O(nW log m)

      解析:对于每个m[i],我们可以分解成2^0+2^1+2^2...+2^k+a(a为m[i]完全分解出来多的),我们知道1,2,4.。。。2^k,可以表示出1到2^(k+1)-1的所有数,也就是说把物品分解后的多重背包就转化成了01背包,效率可以达到(nW),总效率还需乘上log m(分解后多出的物品数)


参考程序:

#include<cstdio>#include<algorithm>#define maxn 11000#define maxw 11000using namespace std;int dp[maxw];int m[maxn],w[maxn],v[maxn];int main(){freopen("hallow.in","r",stdin);freopen("hallow.out","w",stdout);int n,W;scanf("%d%d",&n,&W);for (int i=0;i<n;i++)scanf("%d%d%d",&m[i],&w[i],&v[i]);for (int i=0;i<n;i++){int num=m[i];for (int k=1;num>0;k<<=1){int mul=min(k,num);for (int j=W;j>=w[i]*mul;j--){dp[j]=max(dp[j],dp[j-w[i]*mul]+v[i]*mul);}num-=mul;}}printf("%d",dp[W]);return 0;}



(二)对于上述方法都不可以解决的题目,就需要单独队列维护,理论效率为O(nW),经过检验成立。

      解析:再分析转移方程式:f[j]=max(f[j-k*w[i]]+k*v[i]}(0<=k<=m[i])

             可以看出,如果j mod w[i]取值不同,则其方程式是相互独立的,先设j mod w[i]=c,每个c的做法相同,我们就取c=0的特殊值来研究,其他的c同理即可。

             设a[j]=dp[i][j*w[i]]

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

             因为k是变动的,所以max{}中的常数项不能有k,则提出(j+k)*v[i],原式可化为:

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

             当我们在求f[(j+k)*w[i]]时,明显f[(j+k-1]*w[i]]已经求出,而f[(j+k-1)*w[i]]仅仅是比f[(j+k)*w[i]]的开始多一项,结尾少一项,所以我们可以想到滑动窗口,于是就可以用单调队列维护a[j]-j*v[i]的最大值,于是就可以用O(1)的时间转移到新的状态。


伪代码:

   i=1 to n

    c=0 to w[i]

     while(j*w[i]+a<=W(j++))

       队列维护


参考程序:

#include<cstdio>#include<algorithm>#define maxn 2500#define maxv 1000using namespace std;int dp[maxv+1];int deq[maxv+1];int deqv[maxv+1];int n,V;int m[maxn],w[maxn],v[maxn];int main(){freopen("hallow.in","r",stdin);freopen("hallow.out","w",stdout);scanf("%d%d",&n,&V);for (int i=0;i<n;i++)scanf("%d%d%d",&m[i],&w[i],&v[i]);for (int i=0;i<n;i++){for (int a=0;a<w[i];a++){int s=0,t=0;for (int j=0;j*w[i]+a<=V;j++){int val=dp[j*w[i]+a]-j*v[i];while(s<t && deqv[t-1]<=val)t--;deq[t]=j;deqv[t++]=val;dp[j*w[i]+a]=deqv[s]+j*v[i];if (deq[s]==j-m[i]){s++;}}}}printf("%d",dp[V]);return 0;}


0 0
原创粉丝点击