背包(或分区)算法的变化

时间:2013-12-18 17:08:35

标签: algorithm optimization dynamic-programming combinatorics

我遇到问题的问题如下:

给定一个N个项目的队列,每个项目都有一个权重,以及K个容器的队列。我们需要按照它们的顺序将项目分区到容器。例如,第一个项目只能转到第一个容器,第二个项目可以转到第一个或第二个容器而不是第三个容器(否则第二个容器将没有任何项目)。

我需要创建并实现一种算法来进行某种均匀分布,因此最重的容器必须尽可能轻量级;计算具有这种重量的容器。

我认为这是3分区或背包问题的一些变化。我已经使用动态编程实现了一种可能的分发解决方案,并尝试从其中使用的表中获取计数。但它不够有效(内存太贵),并且获取容器数量的算法不正确。

有人可以解释一下,哪种算法可以解决这个问题?

1 个答案:

答案 0 :(得分:1)

因此,OP的问题一般可以通过this question中给出的DP算法来解决。为了完整起见,我将在此重复它的关键:

  

当我们有项目 s [1],..,s [i] 时,假设 d [i] [j] 是问题的解决方案   和 j 容器。然后:

     
      
  1. d [0] [j] = 0 每个 j
  2.   
  3. d [i] [1] = Sum(s [1],...,s [i]) for   每个
  4.   
  5. d [i] [j] = min(max(d [it] [j-1],Sum(s [i-t + 1],...,s [i]) 1·; = T< = I)
  6.   

然而,天真的实现消耗O(NK)空间,这太多了。幸运的是,请看(3):d[_][j]的值仅取决于d[_][j-1]。这意味着,一旦我们完成了所有d[_][j]的计算,我们就可以使用我们用来存储d[_][j-1]的空间来存储我们即将计算的d[_][j+1]的值。< / p>

由于值d[0][j]都为零,我们也不需要存储它们。因此,我们需要存储的唯一数组是O(N)大小的d[i][1],O(N)大小的数组,它保存j-1次迭代的结果,以及O(N) -sized数组,用于保存我们当前正在计算的j次迭代的结果。总计:O(N)。

编辑:所以第一次,我实际上没有回答关于如何计算最大重量的容器数量的OP的问题。假设w[i][j]保持i,j问题的最大权重,c[i][j]是与最大权重匹配的容器数。然后:

    每个c[0][j] = j
  1. w[0][j] = 0j 每个c[i][1] = 1
  2. w[i][1] = Sum(s[1], .., s[i])i
  3. u等于上面pt(3)中选择的t
    • 如果d[i-u][j-1] > Sum(s[i-u+1], .., s[i])
      • 然后c[i][j] = c[i-u][j-1]w[i][j] = w[i-u][j-1]
      • 因为权重j的{​​{1}}容器比容器Sum(s[i-u+1], .., s[i]中最重的容器轻,其容器1, .., j-1
    • 如果d[i-u][j-1]
      • 然后d[i-u][j-1] < Sum(s[i-u+1], .., s[i])c[i][j] = 1
      • 因为带有w[i][j] = Sum(s[i-u+1], .., s[i])项的j容器是新的最重容器。
    • 如果是s[i-u+1], .., s[i]
      • 然后d[i-u][j-1] == Sum(s[i-u+1], .., s[i])c[i][j] = c[i-u][j-1]+1
      • 因为w[i][j] = d[i-u][j-1]容器的重量与之前最重的容器相同。
  4. 同样,我们只需要使用恒定数量的j大小的数组,总时间O(N)