E13 背包DP 多重背包 单调队列优化

视频链接:https://www.bilibili.com/video/BV1354y1C7SF/

 

C15【模板】单调队列 滑动窗口最值 - 董晓 - 博客园 (cnblogs.com)

Luogu P1776 宝物筛选

#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]);
}

 

posted @ 2023-04-10 09:57  董晓  阅读(650)  评论(0编辑  收藏  举报