RQNOJ 329 二维背包 顺便收集整理一下相关资料

来源:互联网 发布:java数据库书籍 编辑:程序博客网 时间:2024/05/17 00:52

今天做这题,wa了很多次。原来是01背包没学好。

以下是优化空间复杂度后的程序

以下是最直观的01背包

 

一般情况

 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*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[0]为0其它f[1..V]均设为-∞,这样就可以保证最终得到的f[N]是一种恰好装满背包的最优解。
  如果并没有要求必须把背包装满,而是只希望价格尽量大,初始化时应该将f[0..V]全部设为0。
  为什么呢?可以这样理解:初始化的f数组事实上就是在没有任何物品可以放入背包时的合法状态。如果要求背包恰好装满,那么此时只有容量为0的背包可能被价值为0的nothing“恰好装满”,其它容量的背包均没有合法的解,属于未定义的状态,它们的值就都应该是-∞了。如果背包并非必须被装满,那么任何容量的背包都有一个合法解“什么都不装”,这个解的价值为0,所以初始时状态的值也就全部为0了。
  这个小技巧完全可以推广到其它类型的背包问题,后面也就不再对进行状态转移之前的初始化进行讲解。

 

完全背包问题

最优解法—O(VN)
  for i=1..N
  for j=0..V
  f[j]=max{f[j],f[j-c]+w}
这个伪代码与01背包的伪代码只有v的循环次序不同而已。

 

部分内容摘自百度百科