永发信息网

01背包问题

答案:4  悬赏:30  手机版
解决时间 2021-07-25 15:34

pascal语言中的01背包问题的解答

最佳答案
算法分析
  
  对于背包问题,通常的处理方法是搜索。
  用递归来完成搜索,算法设计如下:
  function Make( i {处理到第i件物品} , j{剩余的空间为j}:integer) :integer;
  初始时i=m , j=背包总容量
  begin
  if i:=0 then
  Make:=0;
  if j>=wi then (背包剩余空间可以放下物品 i )
  r1:=Make(i-1,j-wi)+v; (第i件物品放入所能得到的价值 )
  r2:=Make(i-1,j) (第i件物品不放所能得到的价值 )
  Make:=max{r1,r2}
  end;
  这个算法的时间复杂度是O(2^n),我们可以做一些简单的优化。
  由于本题中的所有物品的体积均为整数,经过几次的选择后背包的剩余空间可能会相等,在搜索中会重复计算这些结点,所以,如果我们把搜索过程中计算过的结点的值记录下来,以保证不重复计算的话,速度就会提高很多。这是简单?quot;以空间换时间"。
  我们发现,由于这些计算过程中会出现重叠的结点,符合动态规划中子问题重叠的性质。
  同时,可以看出如果通过第N次选择得到的是一个最优解的话,那么第N-1次选择的结果一定也是一个最优解。这符合动态规划中最优子问题的性质。
  考虑用动态规划的方法来解决,这里的:
   阶段是:在前N件物品中,选取若干件物品放入背包中;
  状态是:在前N件物品中,选取若干件物品放入所剩空间为W的背包中的所能获得的最大价值;
   决策是:第N件物品放或者不放;
   由此可以写出动态转移方程:
  我们用f[i,j]表示在前 i 件物品中选择若干件放在所剩空间为 j 的背包里所能获得的最大价值
  f[i,j]=max{f[i-1,j-Wi]+Pi (j>=Wi), f[i-1,j]}
  这
个方程非常重要,基本上所有跟背包相关的问题的方程都是由它衍生出来的。所以有必要将它详细解释一下:“将前i件物品放入容量为v的背包中”这个子问题,
若只考虑第i件物品的策略(放或不放),那么就可以转化为一个只牵扯前i-1件物品的问题。如果不放第i件物品,那么问题就转化为“前i-1件物品放入容
量为v的背包中”,价值为f[v];如果放第i件物品,那么问题就转化为“前i-1件物品放入剩下的容量为v-c的背包中”,此时能获得的最大价值就是
f[v-c]再加上通过放入第i件物品获得的价值w。
   这样,我们可以自底向上地得出在前M件物品中取出若干件放进背包能获得的最大价值,也就是f[m,w]
  算法设计如下:
  procedure Make;
  begin
  for i:=0 to w do
  f[0,i]:=0;
  for i:=1 to m do
  for j:=0 to w do begin
  f[i,j]:=f[i-1,j];
  if (j>=w) and (f[i-1,j-w]+v>f[i,j]) then
  f[i,j]:=f[i-1,j-w]+v;
  end;
  writeln(f[m,wt]);
  end;
 
 由于是用了一个二重循环,这个算法的时间复杂度是O(n*w)。而用搜索的时候,当出现最坏的情况,也就是所有的结点都没有重叠,那么它的时间复杂度是
O(2^n)。看上去前者要快很多。但是,可以发现在搜索中计算过的结点在动态规划中也全都要计算,而且这里算得更多(有一些在最后没有派上用场的结点我
们也必须计算),在这一点上好像是矛盾的。
  事实上,由于我们定下的前提是:所有的结点都没有重叠。也就是说,任意N件物品的重量相加都不能相等,而所有物品的重量又都是整数,那末这个时候W的最小值是:1+2+2^2+2^3+……+2^n-1=2^n -1
  此时n*w>2^n,动态规划比搜索还要慢~~|||||||所以,其实背包的总容量W和重叠的结点的个数是有关的。
  考虑能不能不计算那些多余的结点……
   优化时间复杂度
  以上方法的时间和空间复杂度均为O(N*V),其中时间复杂度基本已经不能再优化了,但空间复杂度却可以优化到O(V)。
 
 先考虑上面讲的基本思路如何实现,肯定是有一个主循环i=1..N,每次算出来二维数组f[0..V]的所有值。那么,如果只用一个数组
f[0..V],能不能保证第i次循环结束后f[v]中表示的就是我们定义的状态f[v]呢?f[v]是由f[v]和f[v-c]两个子问题递推而来,能
否保证在推f[v]时(也即在第i次主循环中推f[v]时)能够得到f[v]和f[v-c]的值呢?事实上,这要求在每次主循环中我们以v=V..0的顺
序推f[v],这样才能保证推f[v]时f[v-c]保存的是状态f[v-c]的值。伪代码如下:
  for i=1..N
  for v=V..0
  f[v]=max{f[v],f[v-c]+w};
 
 其中的f[v]=max{f[v],f[v-c]}一句恰就相当于我们的转移方程f[v]=max{f[v],f[v-c]},因为现在的f[v-c]
就相当于原来的f[v-c]。如果将v的循环顺序从上面的逆序改成顺序的话,那么则成了f[v]由f[v-c]推知,与本题意不符,但它却是另一个重要的
背包问题P02最简捷的解决方案,故学习只用一维数组解01背包问题是十分必要的。
  事实上,使用一维数组解01背包的程序在后面会被多次用到,所以这里抽象出一个处理一件01背包中的物品过程,以后的代码中直接调用不加说明。
  过程ZeroOnePack,表示处理一件01背包中的物品,两个参数cost、weight分别表明这件物品的费用和价值。
  procedure ZeroOnePack(cost,weight)
  for v=V..cost
  f[v]=max{f[v],f[v-cost]+weight}
 
 注意这个过程里的处理与前面给出的伪代码有所不同。前面的示例程序写成v=V..0是为了在程序中体现每个状态都按照方程求解了,避免不必要的思维复杂
度。而这里既然已经抽象成看作黑箱的过程了,就可以加入优化。费用为cost的物品不会影响状态f[0..cost-1],这是显然的。
  有了这个过程以后,01背包问题的伪代码就可以这样写:
  for i=1..N
  ZeroOnePack(c,w);
   初始化的细节问题
  
  我们看到的求最优解的背包问题题目中,事实上有两种不太相同的问法。有的题目要求“恰好装满背包”时的最优解,有的题目则并没有要求必须把背包装满。一种区别这两种问法的实现方法是在初始化的时候有所不同。
  如果是第一种问法,要求恰好装满背包,那么在初始化时除了f[0]为0其它f[1..V]均设为-∞,这样就可以保证最终得到的f[N]是一种恰好装满背包的最优解。
  如果并没有要求必须把背包装满,而是只希望价格尽量大,初始化时应该将f[0..V]全部设为0。
 
 为什么呢?可以这样理解:初始化的f数组事实上就是在没有任何物品可以放入背包时的合法状态。如果要求背包恰好装满,那么此时只有容量为0的背包可能被
价值为0的nothing“恰好装满”,其它容量的背包均没有合法的解,属于未定义的状态,它们的值就都应该是-∞了。如果背包并非必须被装满,那么任何
容量的背包都有一个合法解“什么都不装”,这个解的价值为0,所以初始时状态的值也就全部为0了。
  这个小技巧完全可以推广到其它类型的背包问题,后面也就不再对进行状态转移之前的初始化进行讲解
全部回答

2.0/1背包

一个旅行者有一个最多能用m公斤的背包,现在有n件物品,它们的重量分别是W1,W2,...,Wn,它们的价值分别为C1,C2,...,Cn.若每种物品只有一件求旅行者能获得最大总价值。

<1>分析说明:

显然这个题可用深度优先方法对每件物品进行枚举(选或不选用0,1控制).

程序简单,但是当n的值很大的时候不能满足时间要求,时间复杂度为O(2n)。按递归的思想我们可以把问题分解为子问题,使用递归函数

设 f(i,x)表示前i件物品,总重量不超过x的最优价值

则 f(i,x)=max(f(i-1,x-W[i])+C[i],f(i-1,x))

f(n,m)即为最优解,边界条件为f(0,x)=0 ,f(i,0)=0;

动态规划方法(顺推法)程序如下:

程序如下:

program knapsack02; const maxm=200;maxn=30; type ar=array[1..maxn] of integer; var m,n,j,i:integer; c,w:ar; f:array[0..maxn,0..maxm] of integer; function max(x,y:integer):integer; begin if x>y then max:=x else max:=y; end; begin readln(m,n); for i:= 1 to n do readln(w[i],c[i]); for i:=1 to m do f(0,i):=0; for i:=1 to n do f(i,0):=0;

for i:=1 to n do for j:=1 to m do begin if j>=w[i] then f[i,j]:=max(f[i-1,j-w[i]]+c[i],f[i-1,j]) else f[i,j]:=f[i-1,j]; end; writeln(f[n,m]); end.

使用二维数组存储各子问题时方便,但当maxm较大时如maxn=2000时不能定义二维数组f,怎么办,其实可以用一维数组,但是上述中j:=1 to m 要改为j:=m downto 1

你好哦楼主~ 很高兴看到你的问题。 但是又很遗憾到现在还没有人回答你的问题。也可能你现在已经在别的地方找到了答案,那就得恭喜你啦。 可能是你问的问题有些专业了,没人会。或者别人没有遇到或者接触过你的问题,所以帮不了你。建议你去问题的相关论坛去求助,那里的人通常比较多,也会比较热心,能快点帮你解决问题。 希望我的回答能够帮到你! 祝你好运。。
|所以,其实背包的总容量W和重叠的结点的个数是有关的。   考虑能不能不计算那些多余的结点……    优化时间复杂度   以上方法的时间和空间复杂度均为O(N*V),其中时间复杂度基本已经不能再优化了,但空间复杂度却可以优化到O(V)。    先考虑上面讲的基本思路如何实现,肯定是有一个主循环i=1..N,每次算出来二维数组f[0..V]的所有值。那么,如果只用一个数组 f[0..V],能不能保证第i次循环结束后f[v]中表示的就是我们定义的状态f[v]呢?f[v]是由f[v]和f[v-c]两个子问题递推而来,能 否保证在推f[v]时(也即在第i次主循环中推f[v]时)能够得到f[v]和f[v-c]的值呢?事实上,这要求在每次主循环中我们以v=V..0的顺 序推f[v],这样才能保证推f[v]时f[v-c]保存的是状态f[v-c]的值。伪代码如下:   for i=1..N   for v=V..0   f[v]=max{f[v],f[v-c]+w};    其中的f[v]=max{f[v],f[v-c]}一句恰就相当于我们的转移方程f[v]=max{f[v],f[v-c]},因为现在的f[v-c] 就相当于原来的f[v-c]。如果将v的循环顺序从上面的逆序改成顺序的话,那么则成了f[v]由f[v-c]推知,与本题意不符,但它却是另一个重要的 背包问题P02最简捷的解决方案,故学习只用一维数组解01背包问题是十分必要的。   事实上,使用一维数组解01背包的程序在后面会被多次用到,所以这里抽象出一个处理一件01背包中的物品过程,以后的代码中直接调用不加说明。   过程ZeroOnePack,表示处理一件01背包中的物品,两个参数cost、weight分别表明这件物品的费用和价值。   procedure ZeroOnePack(cost,weight)   for v=V..cost   f[v]=max{f[v],f[v-cost]+weight}    注意这个过程里的处理与前面给出的伪代码有所不同。前面的示例程序写成v=V..0是为了在程序中体现每个状态都按照方程求解了,避免不必要的思维复杂 度。而这里既然已经抽象成看作黑箱的过程了,就可以加入优化。费用为cost的物品不会影响状态f[0..cost-1],这是显然的。   有了这个过程以后,01背包问题的伪代码就可以这样写:   for i=1..N   ZeroOnePack(c,w);    初始化的细节问题      我们看到的求最优解的背包问题题目中,事实上有两种不太相同的问法。有的题目要求“恰好装满背包”时的最优解,有的题目则并没有要求必须把背包装满。一种区别这两种问法的实现方法是在初始化的时候有所不同。   如果是第一种问法,要求恰好装满背包,那么在初始化时除了f[0]为0其它f[1..V]均设为-∞,这样就可以保证最终得到的f[N]是一种恰好装满背包的最优解。   如果并没有要求必须把背包装满,而是只希望价格尽量大,初始化时应该将f[0..V]全部设为0。    为什么呢?可以这样理解:初始化的f数组事实上就是在没有任何物品可以放入背包时的合法状态。如果要求背包恰好装满,那么此时只有容量为0的背包可能被 价值为0的nothing“恰好装满”,其它容量的背包均没有合法的解,属于未定义的状态,它们的值就都应该是-∞了。如果背包并非必须被装满,那么任何 容量的背包都有一个合法解“什么都不装”,这个解的价值为0,所以初始时状态的值也就全部为0了。   这个小技巧完全可以推广到其它类型的背包问题,后面也就不再对进行状态转移之前的初始化进行讲解
我要举报
如以上问答信息为低俗、色情、不良、暴力、侵权、涉及违法等信息,可以点下面链接进行举报!
大家都在看
诺基亚3610a手机多少钱
为什么空间相册有时照片会显示暂时无法查看?
北京到怀化的火车有哪几趟?
唯一的承诺用英语怎么说
怎样去瞒虫
独数九宫格、我要答案、
请问CF外挂如何查封?
为什么我的电脑老是掉线,必须修复才能好?
蓝领和白领指的是什麽人?
十一月二十九号双色球开奖号码?
江阴那里有大型的动漫周边店
表达对喜欢的人的句子,追一个女孩,对她特别
我喜欢他、被别人知道了,那些女生总喜欢到我
镇江中船设备有限公司质量部电话号码
违法,违规,违纪的事例
推荐资讯
我QQ会员点了自动续费,怎么取消?要具体步骤
谁知道周杰伦的《稻香》
龍OL坐騎怎麼得到
小学五年级上学期分数的题目!急!急!急!
拔了毛的凤凰歇后语,求描写凤凰 诗句
我好不容易写的帖子,没有发表成功,为什么?
what reasons are there for getting student
这2款显卡那个好点啊?
高一数学!!!大家帮帮忙啊!!
出轨的女人还能要吗?
怎么样才能让自己越来越漂亮呢?
开心网是干什么的?
正方形一边上任一点到这个正方形两条对角线的
阴历怎么看 ?