问题描述:一组物品编号1,2,...,N,每个物品重量v[i],价值w[i],挑出若干件物品放入一个能容纳物品重量V背包中,这些物品的总重不超过V,且价值要尽量大。
解题思路:设把1,2,...,i物品挑出若干放入能容纳v重量的背包中,所能产生的最大价值为f[i][v]。如果第i件物品没有放入背包,那么f[i][v]=f[i-1][v];如果第i件物品放入了背包中那么f[i][v]=f[i-1][v-w[i]]+w[i]。为使价值最大化,应取二者较大的:
f[i][v]=max{f[i-1][v],f[i-1][v-v[i]]+w[i]}
上式就是0-1背包问题的状态转移方程,根据该方程很容易写出代码:
#include <iostream>
#include <vector>
#include <iomanip>
using namespace std;
int max(int a, int b)
{
return a > b ? a : b;
}
void print_elems(vector<vector<int>> &v)
{
vector<vector<int>>::iterator it_row;
vector<int>::iterator it_column;
for (it_row = v.begin(); it_row != v.end(); ++it_row)
{
for (it_column = (*it_row).begin(); it_column != (*it_row).end(); ++it_column)
{
cout << *it_column << ' ';
}
cout << endl;
}
}
int main(void)
{
int a[] = { 0, 10, 40, 30, 50 };
int b[] = { 0, 5, 4, 6, 3 };
int max_weight = 10;
vector<int> values(a, a + 5);
vector<int> weight(b, b + 5);
int row = values.size();
int column = max_weight + 1;
vector<vector<int>> grid(row, vector<int>(column, 0));
int i, j;
for (i = 1; i < row; ++i)
{
for (j = 1; j < column; ++j)
{
if (j >= weight[i])
{
grid[i][j] = max(grid[i - 1][j], values[i] + grid[i - 1][j - weight[i]]);
}
else
grid[i][j] = grid[i - 1][j];
}
}
print_elems(grid);
return 0;
}
运行结果:
上述代码的时间复杂度和空间复杂度都是O(V*N)。实际上空间复杂度还可以降到O(V),也就是用一个一维数组来保存数据,需要用到的小技巧就是v要从大到小,也就是说数组f存放前i-1件物品放入重量为1,2,...,V背包中能获得的最大价值。在求前i件物品放入重量为1,2,...,V背包中能获得的最大价值应先求f[i][V],他要用到的f[i-1][V]和f[i-1][V-w[i]]都在f数组中,求出来后,原地放入数组f中,然后更新V-1,...,1,这样就求出了前i件物品放入重量为1,2,...,V背包中能获得的最大价值,且仍保存在f中。
代码:
#include <iostream>
#include <vector>
#include <iomanip>
using namespace std;
int max(int a, int b)
{
return a > b ? a : b;
}
void print_elems(vector<int>& v)
{
for (vector<int>::const_iterator it = v.begin(); it != v.end();++it)
{
cout << *it << ' ';
}
cout << endl;
}
int main(void)
{
int a[] = { 0, 10, 40, 30, 50 };
int b[] = { 0, 5, 4, 6, 3 };
int max_weight = 10;
vector<int> values(a, a + 5);
vector<int> weight(b, b + 5);
int row = values.size();
int column = max_weight + 1;
vector<int> f(column, 0);
int i, j;
for (i = 1; i < row; ++i)
{
for (j = column-1; j > 0; --j)
{
if (j >= weight[i])
{
f[j] = max(f[j], values[i] + f[j - weight[i]]);
}
}
print_elems(f);
}
return 0;
}