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

Luogu P1833 樱花

 

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