01背包问题
问题描述:有个物品与一个体积为的背包,每件物品只能使用一次了,第件物品的体积为, 价值为,求将哪些物品放入背包可使总体及不超过背包容量且价值最大。
思路:用一个二维矩阵f存储最优解,
f[i][j]
代表在对于前i
个物品,背容量为j
时,最佳的选择方案所获得的收益。若j >= v[i]
,则当前面临的决策问题为,第i
个物品取或不取。
- 若不取,则其对应的状态为对于前
i - 1
个物品,背包容量为j
时的最佳收益,即f[i][j] = f[i - 1][j]
- 若取,则其状态为,对于前
i- 1
个物品,背包容量为j - v[i]
时的最佳收益 + 物品i
的收益,即f[i][j] = f[i - 1][j - v[i]] + w[i]
,- 因此状态转移方程式为:
f[i][j] = max(f[i - 1][j], f[i - 1][j - v[i]] + w[i])
const int N = 1010;
int f[N][N], n, m; // n为物品数量,m为背包体积
int v[N], w[N]; //v存储每个物体的体积,w存储每个物体的价值
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 = 1; j <= m; j ++ ){
if (j >= v[i]) f[i][j] = max(f[i - 1][j], f[i - 1][j - v[i]] + w[i]);
}
}
cout << f[n][m] << endl;
}
优化:对于数组f的第i行来说,其取值主要由f数组的第i - 1行与v[i]、w[i]来进行更新,因此,可将f数组优化为一维数组,具体代码如下:
const int N = 1010;
int f[N], n, m;
int v[N], w[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 - v[i]]来更新f[j],所以要倒着循环
f[j] = max(f[j - v[i]] + w[i], f[j]);
}
}
}
完全背包问题
问题描述:有个物品与一个体积为的背包,每件物品都有无限件可用,第件物品的体积为, 价值为,求将哪些物品放入背包可使总体及不超过背包容量且价值最大。
思路:用一个二维矩阵f存储最优解,
f[i][j]
代表在对于前i
个物品,背容量为j
时,最佳的选择方案所获得的收益。若j >= v[i]
,则当前面临的决策问题为,第i
个物品取或不取,以及取多个的问题。
- 若不取,则对应状态为前
i - 1
个物品,背包容量为j
时的最佳方案的收益,即f[i - 1][j]
- 若取,则需要计算取几个时收益最大,并与不取时进行比较,即:
f[i][j] = max(f[i - 1][j], f[i - 1][j - v[i]] + w[i], f[i - 1][j - 2 * v[i]] + 2 * w[i], ..., f[i - 1][j - k * v[i]] + k * w[i]), j - k * v[i] >= 0
由上述公式可知:
f[i][j - v[i]] = max(f[i - 1][j - v[i]], f[i - 1][j - 2 * v[i]] + w[i], f[i - 1][j - 3 * v[i]] + 2 * w[i], ..., f[i - 1][j - (k + 1) * v[i]] + k * w[i])
由上可知:
f[i][j] = max(f[i - 1][j], f[i][j - v[i]] + w[i])
简化公式可得:
f[j] = max(f[j], f[j - v[i]] + w[i])
#include<iostream>
using namespace std;
const int N = 1010;
int f[N], v[N], w[N], n, m;
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]); //更新背包状态
}
}
cout << f[m] << endl;
}