目录
01背包
题目:
代码:
#include<iostream>
using namespace std;
const int N=1e3+6;
int f[N];
int main(){
int n,v;
cin>>n>>v;
int wi,vi;
for(int i=1;i<=n;i++){
scanf("%d%d",&vi,&wi);
for(int j=v;j>=vi;j--){
f[j]=max(f[j],f[j-vi]+wi);
}
}
cout<<f[v];
return 0;
}
完全背包
题目:
代码:
#include<iostream>
using namespace std;
const int N=1e3+6;
int f[N];
int main(){
int n,v;
cin>>n>>v;
int wi,vi;
for(int i=1;i<=n;i++){
scanf("%d%d",&vi,&wi);
for(int j=vi;j<=v;j++){
//注意这里是从前往后进行扫描,因为每次更行f[j]需要用到更新过后的f[j-vi]
f[j]=max(f[j],f[j-vi]+wi);
}
}
cout<<f[v];
return 0;
}
完全背包一维正向扫描证明:
多重背包(朴素写法)
问题:
朴素写法代码:
#include<iostream>
using namespace std;
const int N=1e2+6;
int f[N][N];
int main(){
int n,v;
cin>>n>>v;
int vi,wi,si;
for(int i=1;i<=n;i++){
scanf("%d%d%d",&vi,&wi,&si);
for(int j=0;j<=v;j++){
for(int k=0;k<=si&&k*vi<=j;k++){//k=0即存在f[i][j]=f[i-1][j]
f[i][j]=max(f[i][j],f[i-1][j-k*vi]+k*wi);
}
}
}
cout<<f[n][v];
return 0;
}
多重背包(二进制优化写法):
2024.5.16来更新咯:
PS:二进制优化写法其实很简单,这里先给出题目,再写出原理。
题目:
原理:
简单来说就是对于物品数量拆分为二进制表示,可以证明对于一个数 v ,可以用它 -1,-2,-4,-8、、、 直到不能再减,得到余下的数字。
余下的数字和1,2,4,8、、、 任选数字可以拼凑出所有0到v所有的数字
代码:
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1e5+6;
int n,vsum;
int listw[N];
int listv[N];
int f[N];
int main(){
cin>>n>>vsum;
int w,v,s;
int cnt=0;
for(int i=1;i<=n;i++){
scanf("%d%d%d",&w,&v,&s);
if(s==0) s=vsum/w;//针对特殊情况,即对于一个物品可以选无数次
int t=1;
while(s>t){//对物品可以选择的数量进行二进制处理,即-1,-2,-4、、、
s-=t;
cnt++;
listw[cnt]=t*w;
listv[cnt]=t*v;
t<<=1;
} //对于余下的数进行记录
cnt++;
listw[cnt]=s*w;
listv[cnt]=s*v;
}
//利用滚动数组得出最大值
for(int i=1;i<=cnt;i++){
for(int j=vsum;j>=listw[i];j--){
f[j]=max(f[j],f[j-listw[i]]+listv[i]);
}
}
cout<<f[vsum];
return 0;
}
分组背包:
题目:
15 届蓝桥杯14天国特冲刺营 - 金明的预算方案 - 蓝桥云课 (lanqiao.cn)
原理:
代码:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
const int N=33000;
int f[N];
int v[N];
int imp[N];
int val[N];
int que[N];
vector<int> vc[N];
int n,m;
int main(){
cin>>n>>m;
for(int i=1;i<=m;i++){
scanf("%d%d%d",&v[i],&imp[i],&que[i]);
val[i]=v[i]*imp[i];
if(que[i]){//记录下每个附件的主件是谁
vc[que[i]].push_back(i);
}
}
for(int i=1;i<=m;i++){
if(que[i]==0){
for(int j=n;j>=0;j--){
if(j>=v[i]) //进行分组取最大值
f[j]=max(f[j],f[j-v[i]]+val[i]);
if(vc[i].size()>0&&j>=v[i]+v[vc[i][0]])
f[j]=max(f[j],f[j-v[i]-v[vc[i][0]]]+val[i]+val[vc[i][0]]);
if(vc[i].size()>1&&j>=v[i]+v[vc[i][0]]+v[vc[i][1]])
f[j]=max(f[j],f[j-v[i]-v[vc[i][0]]-v[vc[i][1]]]+val[i]+val[vc[i][0]]+val[vc[i][1]]);
}
}
}
cout<<f[n];
return 0;
}