01背包问题
二维
#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
const int N=1010;
int n,m;//物品数量n和背包容积m都小于1000
int v[N],w[N];//每件物品的体积和价值
int f[N][N]; //f(i,j)表示从前i个物品中选出总体积不超过j的价值的最大值
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>v[i]>>w[i];//完成输入
for(int i=1;i<=n;i++){
for(int j=0;j<=m;j++){
f[i][j]=f[i-1][j];//左边一定存在
if(j>=v[i]) f[i][j]=max(f[i][j],f[i-1][j-v[i]]+w[i]);//右边不一定存在,仅当总体积j大于v[i]时才存在这种情况
}
}
cout<<f[n][m]<<endl;
}
一维
#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
const int N=1010;
int n,m;//物品数量n和背包容积m都小于1000
int v[N],w[N];//每件物品的体积和价值
int f[N];
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>v[i]>>w[i];//完成输入
for(int i=1;i<=n;i++){
for(int j=m;j>=v[i];j--){//从大到小枚举
f[j]=max(f[j],f[j-v[i]]+w[i]);
}
}
cout<<f[m]<<endl;
}
完全背包问题
暴力(会超时)
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
const int N = 1010;
int n,m;
int v[N],w[N];
int f[N][N];
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++) {
cin>>v[i]>>w[i];
}
for(int i=1;i<=n;i++){
for(int j=0;j<=m;j++){
for(int k=0;k*v[i]<=j;k++) //k是第i个物品的个数
f[i][j]=max(f[i][j],f[i-1][j-k*v[i]]+w[i]*k);
}
}
cout<<f[n][m]<<endl;
return 0;
}
优化(二维)
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
const int N = 1010;
int n,m;
int v[N],w[N];
int f[N][N];
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++) {
cin>>v[i]>>w[i];
}
for(int i=1;i<=n;i++){
for(int j=0;j<=m;j++){
f[i][j] = f[i-1][j];
if(v[i]<=j) f[i][j] = max(f[i][j],f[i][j-v[i]]+w[i]);
}
}
cout<<f[n][m]<<endl;
return 0;
}
优化(一维)
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
const int N = 1010;
int n,m;
int v[N],w[N];
int f[N];
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++) {
cin>>v[i]>>w[i];
}
for(int i=1;i<=n;i++){
for(int j=v[i];j<=m;j++){
f[j] = max(f[j],f[j-v[i]]+w[i]);//都是第i层的,不需要改动了
}
}
cout<<f[m]<<endl;
return 0;
}
!!!对于体积j:01背包从大到小循环 完全背包从小到大循环!!!
多重背包问题
暴力写法:三重循环
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstdio>
using namespace std;
const int N=105;
int v[N],w[N],s[N];
int f[N][N];
int main(){
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++)
cin>>v[i]>>w[i]>>s[i];
for(int i=1;i<=n;i++){
for(int j=0;j<=m;j++){
for(int k=0;k<=s[i]&&k*v[i]<=j;k++){
f[i][j]= max(f[i][j],f[i-1][j-v[i]*k]+w[i]*k);
}
}
}
cout<<f[n][m]<<endl;
return 0;
}
二进制优化
将多重背包问题转为01背包问题
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstdio>
using namespace std;
//物品个数最多是1000*log2000
const int N = 1000 * 11 + 5; // 11 为log(2000)向上取整
const int M=2005;
int n,m;
int v[N],w[N];
int f[N];// f[j] 表示体积为j的物品的价值总和最大是多少。
int main(){
cin>>n>>m;
int cnt=0; //为01背包问题中商品的重数
for(int i=1;i<=n;i++){
int a,b,s;
cin>>a>>b>>s;
int k=1;
while(k<=s) {//每次把k个第i个物品打包在一起
cnt++;
v[cnt] = a*k;
w[cnt] = b*k;
s-=k;
k*=2;
}
if(s>0){
cnt++;
v[cnt]=a*s;
w[cnt]=b*s;
}
}
n=cnt;
for(int i=1;i<=n;i++){
for(int j=m;j>=v[i];j--){
f[j]=max(f[j],f[j-v[i]]+w[i]);
}
}
cout<<f[m]<<endl;
return 0;
}
分组背包问题
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const int N=105;
int n,m;
int v[N][N],w[N][N],s[N];
int f[N];
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>s[i];
for(int j=0;j<s[i];j++)
cin>>v[i][j]>>w[i][j];
}
for(int i=1;i<=n;i++){ //枚举每一组
for(int j=m;j>=0;j--){ //从大到小枚举所有体积
for(int k=0;k<s[i];k++){ //枚举所有选择
if(v[i][k]<=j){
f[j]=max(f[j],f[j-v[i][k]]+w[i][k]);
}
}
}
}
cout<<f[m]<<endl;
return 0;
}