01背包 2d
要求
n 个物品每个weight[i] 重量不一样,对应价值value[i],w 容量的背包。求背包能背下的最大价值。(物品不可重复)
分析
vector<vector< int >> dp;
dp[i] [j] :从下标为[0-i]的物品里任意取,放进容量为j的背包,价值总和最大是多少。
两个角度两个递推式
(1)不放物品 dp[i][j] = dp[i - 1][j]
(2)放物品 dp[i][j] = dp[i - 1][j - weight[i]] + value[i]
求两个值的max。
初始化
(1)dp[i][0] = 0 啥都可以取,但是容量为0,总价值必为0;
(2)dp[0][j] = values[0] 容量足够的话(j >= values[0]),只能取第0个。
代码
01二维背包,先遍历物品或者容量都可以
// weight数组的大小 就是物品个数
for(int i = 1; i < weight.size(); i++) // 遍历物品
{
for(int j = 0; j <= bagweight; j++) // 遍历背包容量
{
if (j < weight[i]) dp[i][j] = dp[i - 1][j];
else
{
dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);
}
}
}
01背包 1d
分析
dp[j]:容量为j的背包,所背的物品价值可以最大为dp[j],那么dp[0]就应该是0,因为背包容量为0所背的物品的最大价值就是0。
递推式 dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
注意!!! 或得 dp[j] ,需要提前获得 dp[j - weight] ,为了保证每个物品只使用一次,物品是倒序遍历。
代码
01一维背包,必须遍历物品再容量 !!!
for(int i = 0; i < weight.size(); i++) // 遍历物品
{
for(int j = bagWeight; j >= weight[i]; j--) // 遍历背包容量
{
dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
}
}
完全背包 1d
要求
n 个物品每个weight[i] 重量不一样,对应价值value[i],w 容量的背包。求背包能背下的最大价值。(物品可重复)
分析
vector<vector< int >> dp;
dp[i] [j] :从下标为[0-i]的物品里任意取,放进容量为j的背包,价值总和最大是多少。
与01背包不同的就是,可以重复,01背包为了避免重复,物品遍历是倒序,因此此处可以重复则正序遍历
代码
在完全背包中,对于一维dp数组来说,其实两个for循环嵌套顺序同样无所谓!
// 先遍历物品,再遍历背包
for(int i = 0; i < weight.size(); i++) // 遍历物品
{
for(int j = weight[i]; j < bagWeight ; j++) // 遍历背包容量
{
dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
}
}
排列组合问题
要求
一组数据,任意取若干个,使得取到的值满足要求。求方法的个数
分析
组合不强调顺序,(1,5)和(5,1)是同一个组合。
排列强调顺序,(1,5)和(5,1)是两个不同的排列。
因此,数据可否倒序使用(1 2 1,正序应该是从小到大)成为了关键。
如果求组合数就是外层for循环遍历物品,内层for遍历背包。
如果求排列数就是外层for遍历背包,内层for循环遍历物品。
递推式: dp[i] += dp[i - nums[j]];