题意: n个物品,v[]表示体积,w[]表示价值,m表示背包容量。求背包可得最大价值
初始化:
若要求为恰好装满,则初始化f[0] = 0,f[1...n] = INT_MIN,求答案时需要遍历最后一行取最大值。
若不要求,则f[0...n] = 0,答案为f[m]。
1.01背包问题
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1005;
int v[N],w[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];
for(int i = 1;i <= n ;i ++){
for(int j = 1; j <= m; j ++){
if(j>=v[i])
f[i][j] = max(f[i-1][j],f[i-1][j-v[i]]+w[i]);
else{
f[i][j] = f[i-1][j];
}
}
}
cout<<f[n][m]<<endl;
return 0;
}
空间一维优化(第二层循环逆序m....v[i])
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1005;
int v[N],w[N];
int f[N];
int main()
{
int n,m;
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 >= 1 && j>=v[i]; j --){
f[j] = max(f[j],f[j-v[i]]+w[i]);
}
}
cout<<f[m]<<endl;
return 0;
}
2.完全背包问题
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1005;
int v[N],w[N];
int f[N];
int main()
{
int n,m;
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]);
}
}
cout<<f[m]<<endl;
return 0;
}
3.多重背包问题
1.朴素做法(01背包变形,复杂度n^3)
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 105;
int v[N],w[N],s[N],f[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 = m; j >= v[i]; j--){
for(int k = 1; k * v[i] <= j && k <= s[i]; k ++){
f[j] = max(f[j],f[j - k * v[i]] + k*w[i]);
}
}
}
cout<<f[m]<<endl;
return 0;
}
2.二进制优化
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
const int N = 2050;
int f[N];
struct Goods{
int v,w;
};
int main()
{
int n,m,v,w,s;
vector<Goods> goods;
cin>>n>>m;
for(int i = 0 ; i < n; i ++){
cin>>v>>w>>s;
for(int j = 1 ; j <= s ; j *= 2){
s -= j;
goods.push_back({v*j,w*j});
}
if(s > 0) goods.push_back({v*s,w*s});
}
for(int i = 0 ; i < goods.size(); i ++){
for(int j = m ;j >= goods[i].v; j-- ){
f[j] = max(f[j],f[j - goods[i].v] + goods[i].w);
}
}
cout<<f[m]<<endl;
return 0;
}
4.混合背包问题
tips:先归类为01背包和完全背包,再进行动态规划
s:代表物品种类,若s == -1,为01背包,s == 0,为完全背包,s > 0 ,为多重背包
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
const int N = 1010;
int f[N];
struct Goods{
int s;
int v,w;
};
int main()
{
vector<Goods> goods;
int n,m;
cin>>n>>m;
int s,v,w;
for(int i = 0; i < n; i ++ ){
cin>>v>>w>>s;
if(s == -1){
goods.push_back({-1,v,w});
}
else if( s == 0){
goods.push_back({0,v,w});
}
else{
for(int k = 1 ; k <= s; k *= 2){
s -= k;
goods.push_back({-1, k*v,k*w});
}
if(s > 0) goods.push_back({-1,s*v,s*w});
}
}
for(int i = 0; i < goods.size(); i ++){
if(goods[i].s == -1){
for(int j = m; j >= goods[i].v; j--) f[j] = max(f[j],f[j - goods[i].v]+goods[i].w);
}
else{
for(int j = goods[i].v ;j <= m; j ++) f[j] = max(f[j],f[j - goods[i].v]+goods[i].w);
}
}
cout<<f[m]<<endl;
return 0;
}
5.二维费用的背包问题
f[i][j] 代表体积为i,质量为j的状态的最优解
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 110;
int f[N][N];
int main()
{
int n,V,M;
cin>>n>>V>>M;
for(int i = 0;i < n; i ++){
int v,m,w;
cin>>v>>m>>w;
for(int j = V;j >= v;j --){
for(int k = M;k >= m; k-- ){
f[j][k] = max(f[j][k],f[j-v][k-m] + w);
}
}
}
cout<<f[V][M]<<endl;
return 0;
}