背包DP

突然发现自己dp极其菜,背包一个不会/kk(我没开玩笑)

那全部学一遍。

01背包

问题:n 种物品,每种物品有一个大小 vi,一个价值 ci 可以选择一个或不选,求背包容量为 m 的情况下(指所选物品大小之和小于等于m)选择的物品价值和的最大值。

我们可以设 fi,j 表示在前 i 个物品中选择,背包容量为 j 时可以取到的价值和最大值。

考虑选择一个物品带来的影响:会占用 vi 的容量,并且获得 ci 的价值。不选即无变化。不难推出转移方程。

fi,j=max{fi1,j,fi1,jvi+ci}

发现 fi,j 只会受 fi1,x 的影响,所以考虑省去一维。

fj=max{fj,fjvi+ci}

代码实现:

	for(int i=1;i<=n;++i){
		for(int j=m;j>=v[i];--j){
			f[j]=Max(f[j],f[j-v[i]]+c[i]);
		}
	}

Q1:为什么第二层循环需要倒着枚举。

A1:这样的目的其实是为了保证每个物品最多被选一次。如果正着枚举,会发现 fj 会影响到 fj+vi
进而又影响到 fi+2×vi,这样会使物品能被选无数次。

Q2:没选满容量的情况为最优解,但回答的答案是 fm,这样不会错吗?

A2:答案是不会,因为我们在枚举的时候是对于每个可行容量枚举的,也就是说有就算啥也没选也算作占据一定容量,就可以解决问题。

采药

完全背包

问题:有 n 种物品,每个物品有大小 vi 和 价值 ci,每种物品可以选择无数次,求在背包容量为 m 时的所选物品价值和最大。

在01背包Q1中已经提到了,就不多复述了。

代码实现:

	for(int i=1;i<=n;++i){
		for(int j=v[i];j<=m;++j){
			f[j]=Max(f[j],f[j-v[i]]+c[i]);
		}
	}

疯狂的采药

多重背包

问题:n 种物品,每种物品有一个大小 vi,一个价值 ci 最多可以选择 ti 个,求背包容量为 m 的情况下(指所选物品大小之和小于等于m)选择的物品价值和的最大值。

本质是01背包,只是添加了选择个数的条件,多添加一层循环 k 表示选择的次数即可。转移方程如下:

fj=max{fj,fjk×vi+k×ci}

代码实现:

	for(int i=1;i<=n;++i){
		for(int j=m;j>=v[i];--j){
			for(int k=0;k<=t[i]&&k*v[i]<=j;++k){
				f[j]=Max(f[j],f[j-k*v[i]]+k*c[i]);
			}
		}
	}

多重背包模板

宝物筛选

优化

二进制分组

混合背包

问题:n 种物品,每种物品有一个大小 vi,一个价值 ci 有的可以选择 ti 个,有的只能最多选一个,有的可以选无数个,求背包容量为 m 的情况下(指所选物品大小之和小于等于m)选择的物品价值和的最大值。

上面三种结合枚举物品时判断是什么类型的背包即可,就不多说了。

樱花

多维背包

与其他背包区别在于有多个容量,只需要对于每个容量背包一次即可。(具体是什么背包看题意)

榨取kkksc03

分组背包

每组物品中只能选一个出来。

对于每一组跑01背包即可。

代码实现:

	for(int k=1;k<=T;++k)
	{
		for(int j=m;j>=0;--j)
		{
			for(int i=1;i<=pos[k][0];++i)
			{
				int p=pos[k][i];
				if(j>=w[p]) dp[j]=max(dp[j],dp[j-w[p]]+v[p]);
			}
		}
	}

分组背包

posted @   cbdsopa  阅读(36)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示