问题


给定个物品和一个容量为的背包,对于第个物品有重量,体积和价值。选择若干个物品放入背包中,在不超过背包最大容量的情况下,求背包中物品价值之和的最大值。

过程


为前个物品在背包容量为的情况下所能达到的最大总价值。
对于当第个物品和背包容量,我们有:

  • 如果选择第个物品,则
  • 如果不选择第个物品,则
    对于某件物品,我们要么选,要么不选,因此时有dp[i][j][k] = dp[i - 1][j][k]$$$j \geq w[i] ~and~ k \geq v[i]$时有dp[i][j][k] = max(dp[i - 1][j][k], dp[i - 1][j - w[i]][k - v[i]] + val[i])$$
    滚动数组优化:注意到只需要,因此可以去掉第一维并不断更新自身实现空间。

实现


三维数组

int N, M;
int W, V;
int w[N], v[N], val[N];
int dp[N][M][M];
 
void knapspack()
{
	for(int i = 1; i <= n; i++)
		for(int j = 0; j <= W; j++)
			for(int k = 0; k <= V; k++)
				if(j < w[i] || k < v[i])
					dp[i][j][k] = dp[i - 1][j][k];
				else
					dp[i][j][k] = std::max(dp[i - 1][j][k], dp[i - 1][j - w[i]][k - v[i]] + val[i]);
}

二维滚动数组

int N, M;
int W, V;
int w[N], v[N], val[N];
int dp[N][M];
 
void knapspack()
{
	for(int i = 1; i <= n; i++)
		for(int j = W; j >= w[i]; j--) // 逆序
			for(int k = V; k >= v[i]; k--) // 逆序
				dp[j][k] = std::max(dp[j][k], dp[j - w[i]][k - v[i]] + val[i]);
}