E14 背包DP 混合背包
视频链接:https://www.bilibili.com/video/BV1nV41127ZU/
#include <iostream> using namespace std; const int N=1010,M=10000; int a[M],b[M],c[M]; int f[N]; int main(){ int n, m, v, w, s; cin>>n>>m; int num=1; for(int i=1; i<=n; i++){ scanf("%d%d%d",&v,&w,&s); if(s==0){ //完全背包 a[num]=v; b[num]=w; c[num++]=0; //背包类型 } else{ //多重背包二进制拆分 if(s==-1)s=1; int k=1; while(s>=k){ a[num]=k*v; b[num]=k*w; c[num++]=1; s-=k; k<<=1; } if(s){ a[num]=s*v; b[num]=s*w; c[num++]=1; } } } for (int i=1; i<num; i++){ if(c[i]==1) //01背包 for(int j=m; j>=a[i]; j--) f[j]=max(f[j],f[j-a[i]]+b[i]); else //完全背包 for(int j=a[i]; j<=m; j++) f[j]=max(f[j],f[j-a[i]]+b[i]); } cout<<f[m]; }
#include <iostream> using namespace std; int f[1010]; int main(){ int n, m, v, w, s; scanf("%d %d", &n, &m); for(int i=1; i<=n; i++){ //枚举物品种类 scanf("%d%d%d",&v,&w,&s); if(s!=0){ //01背包或多重背包 if(s==-1) s=1; int num=min(s,m/v); for(int k=1; num>0; k<<=1){ if(k>num) k=num; num-=k; for(int j=m; j>=v*k; j--) f[j]=max(f[j],f[j-v*k]+w*k); } } else{ //完全背包 for(int j=v; j<=m; j++) f[j]=max(f[j],f[j-v]+w); } } printf("%d\n", f[m]); }
// 单调队列优化 #include <iostream> #include <cstring> using namespace std; int n, m; int f[1010],g[1010]; int q[1010]; void ZeroOnePack(int v,int w){ for(int j=m; j>=v; j--) f[j]=max(f[j],f[j-v]+w); } void CompletePack(int v,int w){ for(int j=v; j<=m; j++) f[j]=max(f[j],f[j-v]+w); } void MultiplePack(int v,int w,int s){ memcpy(g,f,sizeof(f)); for(int j=0;j<v;j++){ int h=0,t=-1; for(int k=j;k<=m;k+=v){ if(h<=t && q[h]<k-s*v) h++; if(h<=t) f[k]=max(g[k],g[q[h]]+(k-q[h])/v*w); while(h<=t&& g[k]>=g[q[t]]+(k-q[t])/v*w) t--; q[++t]=k; } } } int main(){ int v, w, s; cin >> n >> m; for(int i=1; i<=n; i++){ scanf("%d %d %d",&v,&w,&s); if(s==-1) ZeroOnePack(v,w); //01背包 else if(s==0) CompletePack(v,w); //完全背包 else MultiplePack(v,w,s); //多重背包 } cout<<f[m]; }