背包DP(待编)
背包DP
0/1背包
有\(n\)件物品,第i件物品的重量为\(w[i]\),价值为\(v[i]\),有一个承重上限为\(t\)的包,在不超出承重的情况下,装的物品价值总和最大为多少?
代码
for (int i=1; i<=n; i++)
{
for (int j=1; j<=t; j++)
{
if (w[i] <=j) f[i][j] =max(f[i-1][j], f[i-1][j-w[i]] +v[i]);
else if[i][j] =f[i-1][j];
}
}
滚动数组优化
for(int i=1;i<=m;i++)
{
for(int j=t;j>=0;j--)
{
dp[j]=max(dp[j-w[i]]+v[i], dp[j]);
}
}
倒着枚举是因为要保证前面的值没有被修改
完全背包
每种物品有无限个
代码
for(int i=1;i<=m;i++)
{
for(int j=1; j<=t; j++)
{
dp[j]=max(dp[j-w[i]]+v[i], dp[j]);
}
}
分组背包
有一些物品,把物品分为\(n\)组,第i组第k个物品的信息为\(w [i] [k]\),\(v [i] [k]\)每组最多选一个物品。对于第i组物品,可以不选,也可以选其中一个,把选每一种的结果求最值。
代码
for (inti=1; i<=n; i++)
{
for (intj=C; j>=1; j++)
{
for (intk=1; k<=cnt[i]; k++)
if (w[i][k] <=j)
f[j] =max(f[j], f[j-w[i][k]] +v[i][k]);
}
}
多重背包
同0/1背包,每种物品有\(cnt[i]\)个。
思路
根据二进制原理,每个数都能拆成2的幂次之和,我们将每个数都拆成二进制。
分组时,用个\(\log_2(cnt[i])\)数就可以组出选\(0\)~$ cnt[i]$个的全部情况,复杂度降到
\[O(\sum{}\log_2cnt[i])
\]
具体的拆分方案,不能全部拆成二的幂次,先拆除来一些,最后再补一个小于或等于最大倍数的余数,这样可以保证拆除的数的和不会超过\(cnt[i]\)。比如拆分\(25\)
正确的拆法:\(1,2,4,8,10\),可以证明它们能组出0 ~ 25的全部情况
代码鸽着
混合背包
就是多重背包,0/1背包,完全背包混合起来,有的只能取一次,有的能取无限次,有的只能取\(k\)次。
只需把前面几个背包混合就行
例题:例题:樱花

浙公网安备 33010602011771号