E13 背包DP 多重背包 单调队列优化
视频链接:https://www.bilibili.com/video/BV1354y1C7SF/
C15【模板】单调队列 滑动窗口最值 - 董晓 - 博客园 (cnblogs.com)
#include <iostream> #include <cstring> using namespace std; const int N=40005; int n,W,w,v,m; int f[N],g[N]; int q[N]; int main(){ scanf("%d%d",&n,&W); //宝物种数,最大载重 for(int i=1;i<=n;i++){ //枚举宝物 memcpy(g,f,sizeof(f)); //f备份到g scanf("%d%d%d",&v,&w,&m); //价值 重量 数量 for(int j=0;j<w;j++){ //分拆成w个类 int h=1,t=0; //对每个类使用单调队列 for(int k=j;k<=W;k+=w){ //滑动窗口[k-m*w,k-w] while(h<=t && g[k]>=g[q[t]]+(k-q[t])/w*v) t--; q[++t]=k; if(q[h]<k-m*w) h++; if(h<=t) f[k]=max(g[k],g[q[h]]+(k-q[h])/w*v); } } } printf("%d\n",f[W]); }
#include <iostream> #include <cstring> using namespace std; const int N=40005; int n,W,w,v,m; int f[N],g[N]; int q[N]; int main(){ scanf("%d%d",&n,&W); //宝物种数,最大载重 for(int i=1;i<=n;i++){ //枚举宝物 memcpy(g,f,sizeof(f)); //f备份到g scanf("%d%d%d",&v,&w,&m); //价值 重量 数量 for(int j=0;j<w;j++){ //分拆成w个类 int h=1,t=0; //对每个类使用单调队列 for(int k=j;k<=W;k+=w){ //滑动窗口[k-m*w,k-w] while(h<=t && q[h]<k-m*w) h++; while(h<=t && g[k]>=g[q[t]]+(k-q[t])/w*v) t--; q[++t]=k; if(h<=t) f[k]=max(g[k],g[q[h]]+(k-q[h])/w*v); } } } printf("%d\n",f[W]); }