01背包二维数组转一维数组
01背包是一种经典的动态规划问题,是指在给定容量的情况下,选择一些物品放入背包,使得物品的总价值最大,且不能超过背包的总重量,01表示选或不选两种状态,每种物品只有这两种状态
具体来说,假设有n件物品和一个容量为weight的背包,每件物品的重量为weight[i],价值为value[i],我们需要选择哪些物品放入背包中,使得价值最大,且总重量不超过weight。定义一个二维数组dp[i][j],表示前i个物品放入容量为j的背包中所能获得的最大价值。则dp[i][j]的计算可以根据以下两种情况进行转移
- 不选第
i
件物品,则dp[i][j] = dp[i-1][j]
- 选第
i
件物品,则dp[i][j] = dp[i-1][j-weight[i]] + value[i]
for(int i = 0; i < 物品数量; i++)
{
for(int j = 0; j < 背包容量; j++)
{
dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);
}
}
空间优化
二维数组变为一维数组,使用滚动数组实现,滚动数组是动态规划中一种用于空间优化的技巧,具体来说就是在计算当前状态的时候,只使用前一阶段的状态值,因此不需要保留全部的状态,只保留一部分即可,通过这种方式可以将多维转化为一维,从而大幅减小占用空间
一维数组中dp[j]
表示的是在背包容量为j
的时候能够装下物品的最大价值
- 不选第
i
件物品,则dp[j] = dp[j]
- 选第
i
件物品,则dp[j] = dp[j - weight[i]] + value[i]
vector<int> dp(物品数量, 0);
for(int i = 0; i < 物品数量; i++)
{
for(int j = 背包容量; j >= weight[i]; j--)
{
dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
}
}
其中背包容量遍历的时候采用了倒序遍历,是因为一维数组记录的是状态值,如果正序遍历,我们不能保证更新dp[j]
的时候dp[j - weight[i]]
已经更新
因为当我们考虑到第i
个物品时,dp[j-w[i]]
表示的是放入第i
个物品后剩余容量为j-w[i]
时的最大价值,而在倒序遍历时,dp[j-w[i]]
已经被更新为当前状态下的最大价值