题目:https://www.acwing.com/problem/content/7/
混合背包是一个比较简单的问题,也就是物品中既有01背包,又有完全背包,还有多重背包,这个时候的多重背包一般使用二进制拆分成01背包来做,因为用单调队列优化的话需要保证初始条件一样,也就是得先读入所有的物品,然后对多重背包进行决策,然后再做01和完全背包,这样的话略显麻烦
先给出多重背包二进制拆分的解法
1 #include<iostream> 2 #include<cstring> 3 #include<algorithm> 4 #include<vector> 5 using namespace std; 6 const int N=1010; 7 int n,m; 8 struct node 9 { 10 int t; 11 int v,w; 12 }; 13 int f[N]; 14 int main(void) 15 { 16 vector<node> ve; 17 cin>>n>>m; 18 for(int i=1; i<=n; i++) 19 { 20 int v,w,s; 21 cin>>v>>w>>s; 22 if(s==-1) 23 { 24 ve.push_back({-1,v,w}); 25 } 26 else if(s==0) 27 { 28 ve.push_back({0,v,w}); 29 } 30 else//二进制拆分 31 { 32 for(int i=1;i<=s;i*=2) 33 { 34 s-=i; 35 ve.push_back({-1,v*i,w*i}); 36 } 37 if(s) 38 ve.push_back({-1,v*s,w*s}); 39 } 40 } 41 for(auto x:ve) 42 { 43 if(x.t==-1) //01背包 44 { 45 for(int i=m;i>=x.v;i--) 46 { 47 f[i]=max(f[i],f[i-x.v]+x.w); 48 } 49 } 50 else //完全背包 51 { 52 for(int i=0;i<=m;i++) 53 { 54 if(i-x.v>=0) 55 { 56 f[i]=max(f[i],f[i-x.v]+x.w); 57 } 58 } 59 } 60 } 61 cout<<f[m]; 62 return 0; 63 }
下面写一下用单调队列优化多重背包,读入数据时可能有点复杂
1 #include<iostream> 2 #include<cstring> 3 #include<algorithm> 4 #include<vector> 5 using namespace std; 6 const int N=1010; 7 int n,m; 8 struct node 9 { 10 int s; 11 int v,w; 12 }; 13 struct ooo 14 { 15 int id; 16 int v; 17 }; 18 int f[N]; 19 ooo qu[N]; 20 int main(void) 21 { 22 vector<node> ve; 23 vector<node> dc; 24 cin>>n>>m; 25 for(int i=1; i<=n; i++) 26 { 27 int v,w,s; 28 cin>>v>>w>>s; 29 if(s==-1) 30 { 31 ve.push_back({-1,v,w}); 32 } 33 else if(s==0) 34 { 35 ve.push_back({0,v,w}); 36 } 37 else 38 { 39 dc.push_back({s,v,w}); 40 } 41 } 42 //多重背包 43 for(auto x:dc)//枚举物品 44 { 45 int num=min(x.s,m/x.v);//窗口大小 46 for(int mod=0;mod<x.v;mod++)//枚举余数 47 { 48 int head=0,tail=-1;//定义队列指针 49 for(int k=0;k<=(m-mod)/x.v;k++)//枚举决策 50 { 51 int z=k,y=f[k*x.v+mod]-k*x.w;//y得减去必然增加的k*x.w,这样的话就能算出同一起跑线的最大值 52 if(tail<head) 53 { 54 qu[++tail]={z,y}; 55 } 56 else 57 { 58 while(tail>=head&&qu[head].id<k-num)head++;//两个出队操作 59 while(tail>=head&&qu[tail].v<=y)tail--; 60 qu[++tail]={z,y};//插入队尾 61 } 62 f[k*x.v+mod]=qu[head].v+k*x.w;//更新结果 63 } 64 } 65 } 66 //01和完全背包 67 for(auto x:ve) 68 { 69 if(x.s==-1) 70 { 71 for(int i=m;i>=x.v;i--) 72 { 73 f[i]=max(f[i],f[i-x.v]+x.w); 74 } 75 } 76 else 77 { 78 for(int i=0;i<=m;i++) 79 { 80 if(i-x.v>=0) 81 { 82 f[i]=max(f[i],f[i-x.v]+x.w); 83 } 84 } 85 } 86 } 87 cout<<f[m]; 88 return 0; 89 }