如何正确布局网格

时间:2012-07-17 05:46:36

标签: ruby algorithm

我有许多不同大小(宽度和高度)的'砖'和一个固定大小的容器。我想从顶部向下移动,尽可能紧凑地布置容器内的砖块。在给定前面的步骤的情况下,我已经选择了网格在任何步骤都应该是最佳的标准。到目前为止,我有以下(低效)代码不起作用:

def fits?(x, y, w, h)
  !((x + w > W) || (y + h > H))
end

def overlaps?(existing, modified)
  existing[:x] + existing[:w] > modified[:x] && existing[:y] + existing[:h] > modified[:y] && modified[:x] + modified[:w] > existing[:x] && modified[:y] + modified[:h] > modified[:y]
end

AXIS = :x

W =  800
H = 6400

sizes = [
  { w: 200 , h: 200 },
  { w: 200 , h: 200 },
  { w: 400 , h: 400 },
  { w: 200 , h: 200 },
  { w: 200 , h: 200 },
  { w: 400 , h: 400 },
  { w: 600 , h: 600 },
  { w: 200 , h: 200 },
  { w: 800 , h: 800 },
]

existing = []

sizes.each do |size|
  size[:x] = 0
  size[:y] = 0

  existing.each do |existing|

    if overlaps?(size, existing)  

      if fits?(x = existing[:x] + existing[:w], y = existing[:y], size[:w], size[:h])
        size[:x] = x
        size[:y] = y
        redo 
      end

      if fits?(x = existing[:x], y = existing[:y] + existing[:h], size[:w], size[:h])
        size[:x] = x
        size[:y] = y
        redo
      end

      case AXIS
      when :x then size[:x] = 0; size[:y] = existing[:y] + existing[:h]
      when :y then size[:y] = 0; size[:x] = existing[:x] + existing[:w]
      end      
    end

  end

  puts "#{size[:x]} , #{size[:y]} , #{size[:w]} , #{size[:h]}"

  existing << size
end

我有什么想法可以解决这个问题?这似乎是贪婪算法的一个主要例子,但我无法弄清楚应该是什么。

2 个答案:

答案 0 :(得分:4)

您的问题是 NP-Hard ,因此没有已知的多项式解决方案

可以显示Subset Sub Problem的简单缩减:

广义子集和问题:给定集合S和整数k,当且仅当存在S的子集时才返回true到k

缩减:给定子集sum (S,k)的实例 - 创建一个大小为(1,k)的容器,每个(1,s)的元素为s } S

很容易看出,当且仅当你能完全填充容器时 - 原始子集和问题的解决方案是正确的,因此上面是多项式减少,问题是NP-Hard。 (注意:“让它尽可能紧凑”的原始问题实际上是这个问题的优化问题,并且仍然是NP-Hard)。

抱歉这个坏消息。
一些替代使用指数解决方案(例如backtracking),启发式近似算法。
请注意,在一维空间中,问题有pseudo-polynomial solution,使用动态编程,但我不认为它可以简单地应用于二维空间(如果有的话)。

答案 1 :(得分:2)

正如amit所指出的,你的问题是NP难的。但是,这不应该阻止你简单地迭代砖块的所有排列,看看它们中哪一个最合适。也就是说,鉴于你没有“太多”砖块。

“太多”的价值主要取决于你的计算速度和你的可用时间,但我的猜测是,比如14的数值都可以。

如果蛮力解决方案太慢,您仍然可以尝试启发式算法或近似算法。

编辑:你的例子砖看起来非常人工。您的砖块尺寸是否符合某些标准,或者它们是完全随意的?也许你可以利用砖块大小的限制,如果有的话。