码迷,mamicode.com
首页 > 其他好文 > 详细

[HDU2191]多重背包

时间:2018-08-29 14:50:35      阅读:136      评论:0      收藏:0      [点我收藏+]

标签:pre   分享图片   main   space   algorithm   价值   \n   多重   F12   

多重背包暴力DP为$O(nV^2)$,n为物品个数,V为背包容量,二进制优化复杂度为$O(nV\log 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\n",f[m]);
21     }
22     return 0;
23 }
二进制优化

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

单调队列的主要思想是从DP方程入手:$$f_{i+j\times v}=max\{f_{i+k\times v}+(j-k)\times w\}=max\{f_{i+k\times 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\n",mx);
30     }
31     return 0;
32 }

 

[HDU2191]多重背包

标签:pre   分享图片   main   space   algorithm   价值   \n   多重   F12   

原文地址:https://www.cnblogs.com/HocRiser/p/9552590.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!