[HDU2191]多重背包

Posted hocriser

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[HDU2191]多重背包相关的知识,希望对你有一定的参考价值。

多重背包暴力DP为$O(nV^2)$,n为物品个数,V为背包容量,二进制优化复杂度为$O(nVlog V)$。

技术分享图片
 1 #include<cstdio>
 2 #include<algorithm>
 3 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
 4 using namespace std;
 5 
 6 const int N=1010;
 7 int T,n,m,v,w,tot,f[N];
 8 
 9 int main(){
10     for (scanf("%d",&T); T--; ){
11         scanf("%d%d",&m,&n);
12         rep(i,0,m) f[i]=0;
13         rep(i,1,n){
14             scanf("%d%d%d",&v,&w,&tot);
15             for (int j=1; tot>=j; tot-=j,j<<=1)
16                 for (int k=m; k>=j*v; k--) f[k]=max(f[k],f[k-j*v]+j*w);
17             if (!tot) continue;
18             for (int k=m; k>=tot*v; k--) f[k]=max(f[k],f[k-tot*v]+tot*w);
19         }
20         printf("%d
",f[m]);
21     }
22     return 0;
23 }
二进制优化

单调队列优化复杂度为$O(nV)$。

单调队列的主要思想是从DP方程入手:$$f_{i+j imes v}=max{f_{i+k imes v}+(j-k) imes w}=max{f_{i+k imes v}-k*w}+j*w$$

v为当前物品的代价,w为价值。j-tot<=k<=j,tot为当前物品的个数。

发现所有转移都是在同一剩余系下做的,所以只要对每个剩余系分别维护一个单调队列即可。

 1 #include<cstdio>
 2 #include<algorithm>
 3 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
 4 using namespace std;
 5 
 6 const int N=1010;
 7 int T,n,m,v,w,tot,q1[N],q2[N],f[N];
 8 
 9 void DP(int v,int w,int tot){
10     for (int i=0; i<v; i++){
11         int st=0,ed=0; q1[0]=q2[0]=0;//单调队列,q1[]存队列内下标,q2[]存队列内的值
12         for (int j=0; j<=(m-i)/v; j++){//f[i+j*v[i]]=max{f[i+k*v[i]]+k*w[i]}+j*w[i](j-tot<=k<=j)
13             if (st<=ed && q1[st]<j-tot) st++;//j-tot<=k<=j
14             int t=f[i+j*v]-j*w;//队列中存f[i+j*v]-j*w
15             f[i+j*v]=max(f[i+j*v],q2[st]+j*w);//更新f[i+j*v]
16             while (st<=ed && t>=q2[ed]) ed--;//将j放入队列
17             q1[++ed]=j; q2[ed]=t;
18         }
19     }
20 }
21 
22 int main(){
23     freopen("hdu2191.in","r",stdin);
24     freopen("hdu2191.out","w",stdout);
25     for (scanf("%d",&T); T--; ){
26         scanf("%d%d",&m,&n); int mx=0;
27         rep(i,0,m) f[i]=0;
28         rep(i,1,n) scanf("%d%d%d",&v,&w,&tot),DP(v,w,tot);
29         rep(i,1,m) mx=max(mx,f[i]); printf("%d
",mx);
30     }
31     return 0;
32 }

 

以上是关于[HDU2191]多重背包的主要内容,如果未能解决你的问题,请参考以下文章

HDU_2191_多重背包

HDU 2191多重背包问题

[HDU2191]多重背包

HDU #2191 买米问题 多重背包及其优化

悼念512汶川大地震遇难同胞——珍惜现在,感恩生活--hdu2191(多重背包模板)

hdu-2191 悼念512汶川大地震遇难同胞——珍惜现在,感恩生活---多重背包