02 背包问题
背包问题属于DP问题,解决DP问题的步骤:1、确定状态变量(函数)2、确定转移方程(递推关系) 3、确定边界条件 4、确定递推顺序
01背包
#include<bits/stdc++.h>
using namespace std;
const int N = 1010;
int w[N], c[N];
int f[N][N];
int main()
{
int n, v;
cin>>n>>v;
for (int i = 1; i <= n; i++) cin>>w[i]>>c[i];
for (int i = 1; i <= n; i++) {
for (int j = 1; j<= v; j++) {
if (j < w[i]) f[i][j] = f[i - 1][j];
else {
f[i][j] = max(f[i - 1][j], f[i - 1][j - w[i]] + c[i]);
}
}
}
cout<<f[n][v];
return 0;
}
是否可以使用一维数组来更新了?
#include<bits/stdc++.h>
using namespace std;
const int N = 1010;
int w[N], c[N];
int f[N];
int main()
{
int n, v;
cin>>n>>v;
for (int i = 1; i <= n; i++) cin>>w[i]>>c[i];
for (int i = 1; i <= n; i++) {
for (int j = v; j >= w[i]; j--) {
f[j] = max(f[j], f[j - w[i]] + c[i]);
}
}
cout<<f[v];
return 0;
}
完全背包
原题地址
解析: 最大价值是物品数量i和背包容量j的函数。设函数f[i][j]表示前i件物品放入容量为j的背包的最大价值。最终的最大价值就是物品数量i从0到N, 背包容量j从0到V时的f[N][V]的值。当前背包容量为j,考虑第i件物品能否放入?是否放入?
1、当前背包容量j < w[i],不能放入,则f[i][j] = f[i - 1][j]; 2、当前背包容量j >= w[i],能放入,但要比较代价,(1) 若第i件物品不放入背包,则f[i][j] = f[i - 1][j],(2) 若第i件物品放入背包,则f[i][j] = f[i][j - w[i]] + c[i]
(对于前i件物品,背包容量为j - w[i]时可能已经放入了第i件物品,容量为j时,还可以再放入第i件物品,所以用f[i][j - w[i]]更新f[i][j],而不是用f[i - 1][j - w[i]]更新f[i][j])
- 状态变量:f[i][j] 表示前i件物品放入容量为j的背包的最大价值
- 转移方程:当j < w[i]时,f[i][j] = f[i - 1][j]; 当j >= w[i]时,f[i][j] = max(f[i - 1][j], f[i][j - w[i]] + c[i]);
- 边界条件:f[i][j] = 0
- 递推顺序:从小到大
#include<bits/stdc++.h>
using namespace std;
const int N = 1010;
int w[N]; // 物品重量
int c[N]; // 物品价值
int f[N][N];
int main ()
{
int N, V;
cin>>N>>V;
for (int i = 1; i <= N; i++) cin>>w[i]>>c[i];
for (int i = 1; i <= N; i++) {
for (int j = 1; j <= V; j++) {
if (j < w[i]) f[i][j] = f[i - 1][j];
else {
f[i][j] = max(f[i - 1][j], f[i][j - w[i]] + c[i]);
}
}
}
cout<<f[N][V];
return 0;
}