【问题标题】:How to optimize the layout of rectangles如何优化矩形的布局
【发布时间】:2009-10-05 13:49:00
【问题描述】:

我有一个动态数量的等比例和大小的矩形对象,我希望它们以最佳方式显示在屏幕上。我可以调整对象的大小,但需要保持比例。

我知道屏幕尺寸是多少。

如何计算将屏幕划分为所需的最佳行数和列数以及将对象缩放到什么大小?

谢谢,

杰米。

【问题讨论】:

  • 它们的大小和方向是否相同?您可以旋转它们还是应该保持比例和方向?
  • 我很确定这是一个 NP 完全问题。
  • @John:这个 NPC 怎么样?我认为它在最坏的情况下是线性的(对可能的列数进行一次迭代,即 [1,N])。

标签: algorithm math layout screen rectangles


【解决方案1】:

假设所有矩形都具有相同的尺寸和方向,并且不应更改。

我们来玩吧!

// Proportion of the screen
// w,h width and height of your rectangles
// W,H width and height of the screen
// N number of your rectangles that you would like to fit in

// ratio
r = (w*H) / (h*W)

// This ratio is important since we can define the following relationship
// nbRows and nbColumns are what you are looking for
// nbColumns = nbRows * r (there will be problems of integers)
// we are looking for the minimum values of nbRows and nbColumns such that
// N <= nbRows * nbColumns = (nbRows ^ 2) * r
nbRows = ceil ( sqrt ( N / r ) ) // r is positive...
nbColumns = ceil ( N / nbRows )

我希望我的数学是正确的,但这与您正在寻找的东西相去甚远;)

编辑: 有一个比例和宽高没有太大区别...

// If ratio = w/h
r = ratio * (H/W)

// If ratio = h/w
r = H / (W * ratio)

然后你又使用 'r' 来查看使用了多少行和列。

【讨论】:

    【解决方案2】:

    Jamie,我将“最佳行数和列数”解释为“多少行和列将提供最大的矩形,与所需的比例和屏幕尺寸一致”。这是解释的简单方法。

    每个可能的选择(矩形的行数和列数)都会产生指定比例的最大可能大小的矩形。循环可能的选择并计算结果大小实现了对可能解决方案空间的简单线性搜索。这里有一段代码可以做到这一点,使用 480 x 640 的示例屏幕和 3 x 5 比例的矩形。

    def min (a, b)
      a < b ? a : b
    end
    
    screenh, screenw = 480, 640
    recth, rectw = 3.0, 5.0
    ratio = recth / rectw
    
    puts ratio
    
    nrect = 14
    
    (1..nrect).each do |nhigh|
      nwide = ((nrect + nhigh - 1) / nhigh).truncate
      maxh, maxw = (screenh / nhigh).truncate, (screenw / nwide).truncate
      relh, relw = (maxw * ratio).truncate, (maxh / ratio).truncate
      acth, actw = min(maxh, relh), min(maxw, relw)
      area = acth * actw
      puts ([nhigh, nwide, maxh, maxw, relh, relw, acth, actw, area].join("\t"))
    end
    

    运行该代码提供以下跟踪:

    1 14 480 45 27 800 27 45 1215
    2 7 240 91 54 400 54 91 4914
    3 5 160 128 76 266 76 128 9728
    4 4 120 160 96 200 96 160 15360
    5 3 96 213 127 160 96 160 15360
    6 3 80 213 127 133 80 133 10640
    7 2 68 320 192 113 68 113 7684
    8 2 60 320 192 100 60 100 6000
    9 2 53 320 192 88 53 88 4664
    10 2 48 320 192 80 48 80 3840
    11 2 43 320 192 71 43 71 3053
    12 2 40 320 192 66 40 66 2640
    13 2 36 320 192 60 36 60 2160
    14 1 34 640 384 56 34 56 1904
    

    由此可见,4x4 或 5x3 布局都会产生最大的矩形。同样清楚的是,矩形大小(作为行数的函数)在极端情况下是最差的(最小的),在中间点是最好的(最大的)。假设矩形的数量适中,您可以简单地用您选择的语言对上述计算进行编码,但一旦结果面积在上升到最大值后开始减少,就立即退出。

    这是一个快速而肮脏(但我希望相当明显)的解决方案。如果矩形的数量变得足够大,您可以通过多种方式调整性能:

    • 使用更复杂的搜索算法(划分空间并递归搜索最佳段),
    • 如果程序过程中矩形的数量不断增加,则保留之前的结果并仅搜索附近的解决方案,
    • 应用一些微积分来获得更快、更精确但不太明显的公式。

    【讨论】:

      【解决方案3】:

      这几乎与 SO 上的kenneth's question 完全相同。他还wrote it up on his blog

      如果您在一个维度上缩放比例以便打包正方形,这将成为同样的问题。

      【讨论】:

      • 该博客条目很棒,并且对于一致的布局更有用。 Kenneth 的问题中的link 对理论最大化有更有用的答案(即旋转正方形以最小化矩形中的空间)。
      【解决方案4】:

      我喜欢这样做的一种方法是使用面积的平方根:

      r = number of rectangles

      w = width of display

      h = height of display

      那么,

      A = (w * h) / r 是每个矩形的面积

      L = sqrt(A) 是每个矩形的底边长度。

      如果它们不是正方形,则只需相应地相乘以保持相同的比率。

      做类似事情的另一种方法是只取矩形数量的平方根。这将为您提供网格的一维(即列数):

      C = sqrt(n) 是网格中的列数

      R = n / C 是行数。

      请注意,其中一个必须 ceiling 和另一个 floor 否则您将截断数字并可能错过一行。

      【讨论】:

        【解决方案5】:

        您提到的行和列表明您设想将矩形排列在一个网格中,可能有几个空格(例如底部的一些行)未填充。假设是这种情况:

        假设您缩放对象,使得(一个未知的数字)n 适合整个屏幕。那么

        objectScale=screenWidth/(n*objectWidth)
        

        现在假设有N个对象,那么会有

        nRows = ceil(N/n)
        

        对象行(其中 ceil 是Ceiling function),将占用

        nRows*objectScale*objectHeight
        

        垂直高度。我们需要找到n,并且想选择最小的n,使得这个距离小于screenHeight

        上限函数的存在使n 的简单数学表达式变得更加复杂。如果列数将相当小,找到n 的最简单方法可能就是循环增加n 直到满足不等式。

        编辑:我们可以从

        的上限开始循环
        floor(sqrt(N*objectHeight*screenWidth/(screenHeight*objectWidth)))
        

        对于 n,然后向下工作:然后在 O(sqrt(N)) 中找到解决方案。一个 O(1) 的解决方案是假设

        nRows = N/n + 1
        

        或采取

        n=ceil(sqrt(N*objectHeight*screenWidth/(screenHeight*objectWidth)))
        

        (Matthieu M. 的解决方案)但这些都具有n 的值可能不是最优的缺点。

        N=0N=1 和对象的纵横比为objectHeight/objectWidth &gt; screenHeight/screenWidth 时会出现边界情况——这两种情况都很容易处理。

        【讨论】:

        • 问题是如何优化计算'n'。当然,如果我知道我要在屏幕上放置多少个对象,那么计算其他所有内容就很简单了——但这是一个未知数。问题是如何计算最佳的“n”以及所需的行数 - 然后是结果对象的宽度和高度......干杯,杰米。
        • 绝对 - 请参阅编辑:我认为最佳 n 的解析表达式是不可能的,但可以最大限度地减少搜索。
        猜你喜欢
        • 2010-11-18
        • 2012-12-21
        • 1970-01-01
        • 2017-09-12
        • 2018-09-05
        • 2012-06-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多