问题描述:
给定n种物品和一背包。物品i的重量是wi,其价值为vi,背包的容量为C。问应如何选择装入背包的物品,使得装入背包中物品的总价值最大?(在选择装入背包的物品时,对每种物品i只有两种选择,即装入背包或不装入背包。不能将物品i装入背包多次,也不能只装入部分的物品i。因此,该问题称为0-1背包问题)
算法描述:
由0-1背包问题的最优子结构性质,我们可以建立m(i, j)的递归表达式如下:
基于以上讨论,当wi(1≤i≤n)为正整数时,用二维数组m[ ][ ]来存储m(i,j)的相应值,可设计解0-1背包问题的动态规划算法Knapsack如下:
template<class Type>
void Knapsack(Type v, int w, int c, int n, Type** m)
{
int jMax = min(w[n] - 1, c);
for (int j = 0; j <= jMax; j++)
m[n][j] = 0;
for (int j = w[n]; j <= c; j++)
m[n][j] = v[n];
for (int i = n - 1; i > 1; i--) {
jMax = min(w[i] - 1, c);
for (int j = 0; j <= jMax; j++)
m[i][j] = m[i + 1][j];
for (int j = w[i]; j <= c; j++)
m[i][j] = max(m[i + 1][j],
m[i + 1][j - w[i]] + v[i]);
}
m[1][c] = m[2][c];
if (c >= w[1])m[1][c] = max(m[1][c],
m[2][c - w[1]] + v[1]);
}
//构造最优解
template<class Type>
void Traceback(Type** m, int w, int c, int n, int x)
{
for (int i = 1; i < n; i++)
if (m[i][c] == m[i + 1][c])x[i] = 0;
else { x[i] = 1; c -= w[i]; }
x[n] = (m[n][c]) ? 1 : 0;
}
按上述算法Knapsack计算后,m[1 ][c ]给出所要求的0-1背包问题的最优值。相应的最优解可由算法Traceback计算如下。如果m[1 ][ c]=m[ 2][c ],则x1=0,否则x1=1,当x1=0时,由mm[ 2][c ]继续构造最优解。当x1=1时,由m[ 2][c -w1]继续构造最优解。依次类推,可构造出相应的最优解(x1,x2,···,xn)。
时间复杂度:0-1背包问题的动态规划算法的时间复杂度为O(nW),其中n为物品数量,W为背包容量。