E14 背包DP 混合背包_哔哩哔哩_bilibili
#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];
}
P1833 樱花 - 洛谷