背包dp进阶

背包dp

01背包#

有若干物品,每个物品只有一个,要么选要么不选,每个物品有 一个容积和价值。

solution:

fi,V 表示当前考虑到第 i 个物品时,总容积为 V 的最大 价值。每次转移的时候枚举前面的容积和当前物品选或者不选

总复杂度 O(nV)

如果价值较小时,可以考虑将价值放入状态,记录容积的最小值。 滚动数组优化

完全背包#

有若干种物品,每种物品有无限个,每个物品有一个容积和一个价值,在不超过背包大小的情况下放入价值尽可能大的物品

solution:

01 背包一个样,因为 01 背包避免一个背包选多次,所以就倒序枚举,那完全背包就正序枚举就好了

多重背包#

有若干种物品,每种物品有 ai 个,每个物品有一个容积和一个价值。在不超过背包大小的情况下放入价值尽可能大的物品

solution:

二进制优化:

因为任何数都可以表示成某些 2n 加和来表示,所以把 ai 进行二进制拆分,将 2k 个物品看做一个整体,按照 01 背包做

for(int i = 1; i <= n; i++){
   int num = min(a[i], V / w[i]); 
   for(int k = 1; num > 0; k <<= 1){
   	   if(k > num) k = num;
   	   num -= k;
   	   for(int j = V; j >= w[i] * k; j--)
   	   	f[j] = max(f[j], f[j - w[i] * k] + v[i] * k);   
   }  
}

单调队列优化

[HNOI2007] 梦幻岛宝珠#

solution

01背包板子题目,但花费和价值都特别的大,但花费都能表示成 a2b 的形式 a10,b30

从题目的特殊条件考虑,我们可以考虑对所有 b 相同的物品进行背包,再进行合并

这样把每个物品花费的 2b 提出来,花费就可以看做 a ,价值不变,直接 01 背包就好了

这样就可以求出在各种容量下,只放 b 相同的物品的最大收益

可以理解为给你一个 b 现在你已经知道在任何容量下只放 a2b 这种物品的最大收益

很显然,背包里面不可能只放 b 相同的物品,那么怎么把 b 不同的背包进行合并?

令上方求得每类背包为 f[i][j] ,表示对于 bi 的物品背包,容量为 j 的最大价值

再设一个数组 g[i][j] 表示使用 b0i 的物品进行背包,b 的价值所占空间为 j 时,剩余物品剩余物品(即 b1i1)所占空间为 m&((1<<i)1) 的最大价值。

考虑转移:

g[i][j]=max(g[i][j],f[i][jk]+g[i1][min(10n,k2+(V>>(i1))&1)]

  • 10n 因为 a10 所以每一位上的最大容量为 10n
  • k2 上一位拿出来剩下的空间拿给下一位需要 *2(进制向右移)
  • (V>>(i1))&1) 判断第 i 位是不是 1 ,也就是再把这一位上的空间加上

最后答案为 g[V][1]

消失之物#

solution:

卷积问题:分别预处理一个前缀背包和一个后缀背包

f[i][j] 表示前 i 个物品填满容量为 j 的背包的方案数

g[i][j] : 表示后 i 个物品填满容量为 j 的背包的方案数

ans=j=0S=f[i1][j]g[ni][Sj]

复杂度

On2m

考虑背包转移式子

如果 jw[i] f[j]=f[jw[i]]

每个 j 都是由 f[jw[i]] 倒序转移过来的,现在去除一个物品那就正序除去这个物品就好了

 memcpy(g, f, sizeof f);
   	  for(int j = 1; j <= m; j++){
   	  	  if(j >= w[i])g[j] = (g[j] - g[j - w[i]] + 10) % 10;
		  printf("%d", g[j]);
	  }

P1450[HAOI2008]硬币购物#

solution

暴力直接每天一次多重背包,时间复杂度 O(dsn)一周都跑不完

考虑如果没有硬币数量的限制,那就是个完全背包了

换一种想法:所有在限制之内的方案数 = 所有方案数 - 不合法的方案数

一种神奇的思想:

考虑对一枚硬币限制

假设一个货币一次购买的使用上限为 di, 我们现在让它使用 di+1 次,用剩下的其他硬币对 f[sc[i](di+1)] 的空间跑完全背包,那么跑出来的方案就都是不合法的,那么合法的方案数就是总的方案数减去跑出来的方案数,这就是对一枚硬币的限制情况

对四枚硬币限制:

直接用 f[S] 减去分别对四种硬币的限制情况??

显然不对,当对一个硬币起限制情况的时候,减去了这个硬币超过范围的情况,但也可能减去对其他硬币超过范围的情况

所以应该为容斥:

根据Y_B_Y 的博客 理解==

ans=f[s]card(A)card(B)card(C)card(D)  +card(AB)+card(AC)+card(AD)  +card(BC)+card(BD)+card(CD)  card(ABC)card(ABD)  card(ACD)card(BCD)  +card(ABCD)

怎么求?

  • 把式子抄上去,打表计算
  • 发现集合里面是个全排列,可以直接二进制枚举

BZOJ4976宝石镶嵌#

n 个物品,每个物品价值依次为 w1,w2,...,wn 背包容量为 nk ,价值为背包中的所有物品价值按位或的结果,求怎样使得价值最大

n,wi105,k100

solution

考虑如果 nk17,那么我们对于每一位都选一个对应位为 1 的宝石即可。

只需要考虑 nk<17 的情况,即 n<117

直接背包,f[i] 表示或为 i 的时候所需要的最小的数

时间复杂度:O(217k)

for (int i = 1;i <= n; i++)
    for (int j = (1 << 17);j>=0;j++)
        f[i + 1][j | w[i]] = min([f[i+1][j | w[i]], f[i][j]+1)
for (int i = (1 << 17);i > 0; i--)
    if (f[n + 1][i] <= n - k) printf("%d",f[n + 1][i]);

posted @   Dita  阅读(109)  评论(5编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话
点击右上角即可分享
微信分享提示
主题色彩