本文已参与「新人创作礼」活动,一起开启掘金创作之路。
一、01背包(每个物品放一次)
一维
有N个物品 背包总容量为V 每个物品有w(重量)v(价值) 每个物品放一次 在不超过V的前提下求背包所装最大价值
for(int i=1;i<=N;i++){
for(int j=V;j>=w[i];j--)
f[j]=max(f[j],f[j-w[i]]+v[i]);
}
二维
有N个物品 背包总容量为V,价值总和T 每个物品有v(重量)v(价值) t(价钱) 每个物品放一次 在不超过V且不超过T的前提下求背包所装物品最多价钱
for(int i=1;i<=N;i++){
for(int j=V;j>=v[i];j--){
for(int k=T;k>=t[i];k--)
f[j][k]=max(f[j][k],f[j-v[i]][k-t[i]]+r[i]);
}
}
二、完全背包(物品可以放无限次)
有N个物品 背包总容量为V 每个物品有w(重量)v(价值) 每个物品放无限次 在不超过V的前提下求背包所装最大价值
for(int i=1;i<=N;i++){
for(int j=w[i];j<=V;j++)
f[j]=max(f[j],f[j-w[i]]+v[i]);
}
三、多重背包
有N个物品 背包总容量为V 每个物品最多有s件,w(重量)v(价值) 在不超过V的前提下求背包所装最大价值
for(int i=1;i<=N;i++){
for(int j=V;j<=w[i];j--){
for(int k=1;k<=s[i]&&k*w[i]<=j;k++)
f[j]=max(f[j],f[j-k*w[i]]+k*v[i])
}
}
当s>20000 N>1000 时 二次进制存储优化 拆分s 然后再01背包
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
struct Good{//定义结构体
int w,v;
};
const int S=2010;
int f[S];
int main(){
int N,V;
cin>>N>>V;
vector<Good> goods;//不确定大小 用容器
for(int i=1;i<=N;i++){
int s,w,v;
cin>>s>>w>>v;
for(int k=1;k<=s;k*=2){
s=k;
goods.push_back({w*s,v*s});
}
if(s>0) goods.push_back({w*s,v*s});//不是2的整n次方倍
}
N=goods.size();
for(int i=1;i<=N;i++)
for(int j=V;j>=goods[i].w;j--)
f[j]=max(f[j],f[j-goods[i].w]+goods[i].v);
cout<<f[V]<<endl;
return 0;
}
单调队列优化
四、组合背包
一共有N组数据 背包容量V 对于每组数据有重量m,价值v, s 有三种数据 s==-1 每个物品只能用依次 s==0 每个物品可用无限次 s 每个物品有s个
二进制容器存储 ,遍历0~N是判断用01背包还是完全背包
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
struct Good{
int pd;
int m,v;//每个物品所占体积和价值
};
const int SS=1005;
int f[SS];
int N,V;//数量 体积
vector<Good> goods;
int main(){
cin>>N>>V;
for(int i=0;i<N;i++){
int m,v,s;
cin>>m>>v>>s;
if(s==-1) goods.push_back({-1,m,v});
else if(s==0) goods.push_back({0,m,v});
else{
for(int k=1;i<=s;i*=2){
s-=k;
goods.push_back({-1,m*k,v*k});
}
if(s>0) goods.push_back({-1,m*s,v*s});
}
}
N=goods.size();
for(int i=0;i<N;i++){
if(goods[i].pd==0)
{
for(int j=goods[i].m;j<=V;j++)
f[j]=max(f[j],f[j-goods[i].m]+goods[i].v);//01背包
}
else{
for(int j=V;j>=goods[i].m;j--)
f[j]=max(f[j],f[j-goods[i].m]+goods[i].v);//完全背包
}
}
cout<<f[V]<<endl;
return 0;
}
五、分组背包
有n个物品,物品分类有m种 每种物品只能选一个 每件物品体积为w 价值为v 求在不超过背包体积V 的前提先 背包的最大价值。
for(int i=0;i<m;i++){
for(int j=V;j>0;j--){
for(int k=0;k<x[i];k++)//x 是每类物品的个数
if(j>w[i][k])
f[j]=max(f[j],f[j-w[i][k]]+v[i][k]);//w[i][k] 第i类物品第k个的体积 w[i][k] 第i类物品第k个的价值
}
}
#include<iostream>
using namespace std;
int m,n;
int a[1005],b[1005],c[105][20],f[1005],cc[101],cn=0;
int main(){
cin>>m>>n;
for(int i=1;i<=n;i++){
int C;
cin>>a[i]>>b[i]>>C;
cn=max(cn,C);
cc[C]++;
c[C][cc[C]]=i;
}
for(int i=1;i<=cn;i++){
for(int j=m;j>=0;j--){
for(int k=1;k<=cc[i];k++){
if(j>=a[c[i][k]])
f[j]=max(f[j],f[j-a[c[i][k]]]+b[c[i][k]]);
}
}
}
cout<<f[m]<<endl;
return 0;
}