ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

背包

2022-08-14 02:01:10  阅读:124  来源: 互联网

标签:件物品 20 01 int 背包 dp


背包是线性DP中一类重要而特殊的模型。

没有骚话水了下面就直入主题,看一下DP中的“常客”————背包问题。
以01背包的模板题为例。

有N件物品和一个容量为V的背包。第i件物品的体积是Ci,得到的价值是Wi。求解将那些物品装入背包可使装入背包的价值总和最大。

题目很简短(当然对于各个大犇也很简单但是我想水),首先还是看一下阶段如何来定义,这里我们采用一个二元数组dp[i][j]来表示从前i件物品中挑选了一些物品,其所用体积为j时,物品的最大价值和。
这样我们就不需要理会前面已完成的部分,而只需考虑如何用其来更新就行。
假设我们已经知道有关dp[i][j]的前面的阶段,我们该如何得出dp[i][j]呢?

  • 如果不取第i件物品 dp[i][j]=dp[i-1][j]
  • 如果取第i件物品 dp[i][j]=dp[i-1][j-Ci](当然需要满足j>=Ci
总的来看,我们只需要像下面这样就可实现转移
for(int i=1;i<=n;i++){
	dp[i][j]=dp[i-1][j];
	for(int j=c[i];j<=v;j++)
		dp[i][j]=max(dp[i][j],dp[i-1][j-c[i]]+w[i]);
}

但是作为一名有着三十年代码经验的oler为了节省空间,我们还可以这样……

for(int i=1;i<=n;i++)
	for(int j=v;j>=c[i];j--)
		dp[j]=max(dp[j],dp[j-c[i]]+w[i]);

为什么可以省掉一维呢?
仔细查看,我们发现dp[i][j]的值可以看作是“一行一行地传递下来的”,且每一行只跟上一行有关,那么我们就可以让其“一行一行地覆盖”,从而只需一维来节省空间。
但为什么要让j倒着来呢?很简单,dp[j]只可能被dp[x(x<j)]更新,只要我们倒着来,那么为遍历过的就会保持着“上一行”的状态,不然,有可能dp[x(x<j)]已经被更新(即已经是取过第i件物品的状态),再用其更新就会违背01背包问题的定义。
值得一提的是,完全背包问题的模板就是把01背包每件只能取一件换成可无限取。
那么,此时只需这样……

for(int i=1;i<=n;i++)
	for(int j=c[i];j<=v;j++)
		dp[j]=max(dp[j],dp[j-c[i]]+w[i]);

对,就是把内层循环改回正的就行了!
But why?(好吧,大家都知道,这样问显得鄙人很蠢……)
因为正着来,dp[x(x<=j)]已经被遍历过,说明已经是考虑过是否取该件物品的,也就是可能取过很多次,符合完全背包的定义。
除了01和完全外,背包还有多重与分组。
多重背包,其实就是01背包的再魔改:将取一件改为取限定数件。
处理也很简单,就是将其件数进行拆分。那么,怎么拆?
且看我抄书分析————
我们找到一个数p,使得20+21+22+……+2p<=s(s为数量),再令x=s-20+21+22+……+2p,那么,我们就能用20到2p和x这些数构建出小于等于s的任意数。
为什么?因为x显然小于2(p+1),而20到2p可以构造出1到2(p+1)-1中的任意数,此时加上x,就可将任意构造的范围扩大到1到s。
所以只要按照这种方法,把该件物品分成(p+2)件物品(此时物品体积为20*C~i~到2pCi与xCi,且每件只能取一件),就能将问题变为01背包,再进行解决。
那么,代码就不需要贴了。其实是没写
最后,再水一下介绍一下多重背包。
额,其实吧,这货还是01背包魔改……只要把i件物品改为有i组物品,每组只取一件。
那么模板也是小改一下就行。

for(int i=1;i<=n;i++)
	for(int j=v;j>=0;j--)
		for(int k=1;k<=s[i];k++)
			if(j>=c[i][k])
				dp[j]=max(dp[j],dp[j-c[i][k]]+w[i][k]);

注意k只能在最内层,因为要保证每组只能选一件,放在里面并配合j的倒序循环,只会被“上一层”更新,从而实现每组只取一件的目的。

当然这些只是最简单的模板,一般题目都会在其基础上进行“修饰”或“难度加倍”,那就应对其内在的细节把握得更清晰。
最后,终于水完了!!!

标签:件物品,20,01,int,背包,dp
来源: https://www.cnblogs.com/hh--/p/16583693.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有