Объединение прямоугольников в максимально квадратное расположение - PullRequest
0 голосов
/ 04 декабря 2008

Моя ситуация

  • у меня есть N прямоугольников
  • Все прямоугольники имеют одинаковую форму (например, 2 дюйма в ширину и 1 дюйм в высоту). Давайте обозначим этот размер как Sw и Sh для ширины и высоты
  • Я хочу расположить эти прямоугольники в сетке таким образом, чтобы канавки полностью располагались сверху и рядом друг с другом - как показано в электронной таблице
  • Что мне нужно, так это: Учитывая N, Sw и Sh, каково количество строк (R) и столбцов (C), в которых эти стеки были бы собраны в максимально квадратное расположение
  • Понятно, что R & C может предоставить больше ячеек, чем необходимо (например, если N = 15, Sw = 1, Sh = 1, то R = 4, C = 4, что дает 16 «слотов» для 15 прямоугольников - что все в порядке.
  • Если Sw = Sh, тогда моих скромных математических навыков достаточно - когда их прямоугольники имеют различную ширину и высоту - честно говоря, это вне меня.

Некоторые заметки

  • Да, я прочитал этот вопрос: Сложив прямоугольники, чтобы занять как можно меньше места и нет, это не помогло. И это не тот же вопрос. Этот вопрос касается прямоугольников, которые могут быть разных размеров, в этом вопросе прямоугольники имеют одинаковый размер
  • Да, я искал на wolfram.com и т. Д., И мне не повезло
  • У меня нет сильных математических знаний, поэтому способ, которым я формулирую эту проблему, сам по себе может помешать мне найти ответ - я пробовал связанные поиски, связанные с разбиением на листы, анализом, разложением, и не имел никакого успеха там либо

Некоторые примеры

the * indicates the edges of the rects
the | indicates that a cell is "filled-in"
Notice that not all R*C cells are filled in, but only and exactly N cells

IF N=1, Sw=2, Sh=1 THEN R=1, C=1

********
*||||||*
********

IF N=2, Sw=2, Sh=1 THEN R=2, C=1

********
*||||||*
********
*||||||*
********

IF N=3, Sw=2, Sh=1 THEN R=2, C=2


***************
*||||||*      *
***************
*||||||*||||||*
***************

IF N=4, Sw=2, Sh=1 THEN R=2, C=2


***************
*||||||*||||||*
***************
*||||||*||||||*
***************

IF N=5, Sw=2, Sh=1 THEN R=3, C=2


***************
*||||||*      *
***************
*||||||*||||||*
***************
*||||||*||||||*
***************

Реализация завтрашнего ответа Aaronof

# Implementation of AaronofTomorrow's answer
# implemented in python 2.6
# reasonable output
# works in constant time

import math

def f( N, Sw, Sh ) :
    cols = math.sqrt( float(N) * float(Sh) / float(Sw) )
    cols = round(cols)
    rows = float(N) / float(cols)
    rows = math.ceil(rows)
    return (int(cols),int(rows))

Еще одна реализация, вдохновленная ответом Уилла (Обновлено 2008-12-08) - это та, которую я наконец-то использовал

# Another implementation inspired by Will's answer
# implemented in python 2.6
# reasonable output - a bit better in yielding more squarelike grids
# works in time proportional to number of rects
#
# strategy used it to try incrementaly adding a rect.
# if the resulting rect requires more space then two
# possibilities are checked - adding a new row or adding a new col
# the one with the best aspect ratio (1:1) will be chosen 


def g( N, Sw, Sh ) :
    slope = float(Sh)/float(Sw)
    cols = 1
    rows = 1
    for i in xrange( N ) :
        num_to_fit =i+1
        allocated_cells= cols* rows
        if ( num_to_fit <= allocated_cells ) :
            pass # do nothing
        else :
            hc,wc = float(Sh * rows), float(Sw * (cols+1))
            hr,wr = float(Sh * (rows+1)), float(Sw * cols)
            thetac = math.atan( hc/wc)
            thetar = math.atan( hr/wr)
            alpha = math.pi/4.0
            difr = abs(alpha-thetar)
            difc = abs(alpha-thetac)
            if ( difr < difc ) :
                rows = rows +1
            else:
                cols = cols + 1

    return (cols,rows)

Ответы [ 4 ]

2 голосов
/ 04 декабря 2008

Опираясь на ответ Уилла Дина, найдите производную его формулы (по отношению к nCols):

-N * Sh / nCols + Sw

Затем установите его на 0 и решите для nCols, что дает:

nCols = sqrt (N * Sh / Sw)

Округлите, и у вас должно быть оптимальное количество столбцов:

cols = round (sqrt (N * Sh / Sw))
ряды = ceil (н / кол)

1 голос
/ 04 декабря 2008

Я думаю, вы обнаружили, что «наиболее квадратный» - это шаг на пути к «наиболее круговидному», то есть точке, в которой окружность (длина периметра) будет минимальной.

Ваша окружность составляет 2 * nRows * Sh + 2 * nCols Sw. Вы знаете, что nRows nCols> = N, и я думаю, что упрощение до nRows * nCols = N будет в порядке в следующем бите.

Не пытаясь это сделать, я думаю, что вы могли бы тогда с пользой попытаться найти (the) минимум функции:

N/nCols*Sh + nCols*Sw

Не знаю, сработает ли что-нибудь из этого, но это позволило мне отложить начало моего рабочего дня на 5 минут, так что это не потеря.

0 голосов
/ 04 декабря 2008

Во-первых, прямоугольники или прямоугольники особого случая с истинным квадратом, где размерность равна нулю.

В противном случае, для простоты объяснения, построим его итеративно:

    add a new row until height is greater than width
    add a new column until width is greater than height

, который в коде может выглядеть так:

    // place the first tile as an initialisation
    int tiles = num_tiles - 1;
    int rows = 1;
    int columns = 1;
    int width = sx;
    int height = sy;

    int i=1; // just because we're curious how many iterations we have

    // build the near-square
    while(tiles > 0) {
        while((tiles > 0)
        && ((width + sx) <= (height + sy))) {
            // add a column
            tiles -= rows;
            columns++;
            width += sx;
        i++;
        }
        while((tiles > 0)
        && ((height + sy) < (width + sx))) {
            // add a row
            tiles -= columns;
            rows++;
            height += sy;
        i++;
        }
    }

    // done
    printf("%d = %d (%dx%d) = %dx%d (%dx%d) in %d\n",
    num_tiles,tiles,sx,sy,rows,columns,width,height,i);

и некоторые результаты:

100 = -5 (10x20) = 7x15 (150x140) in 21
1000 = -12 (10x20) = 22x46 (460x440) in 67
10000000 = -1628 (10x20) = 2236x4473 (44730x44720) in 6708
200 = 0 (7x13) = 10x20 (140x130) in 29
2000 = -13 (7x13) = 33x61 (427x429) in 93
20000000 = -3790 (7x13) = 3282x6095 (42665x42666) in 9376
400 = -14 (17x13) = 23x18 (306x299) in 40
4000 = -15 (17x13) = 73x55 (935x949) in 127
40000000 = -192 (17x13) = 7232x5531 (94027x94016) in 12762

наихудший случай O (n) для очень очень тонких прямоугольников или небольшого числа прямоугольников. Но O (sqrt (n)) в общем случае?

0 голосов
/ 04 декабря 2008

Если количество прямоугольников не ограничено, вам нужно найти LCD (наименее общий знаменатель) для Sw и Sh. Затем вы можете разделить его на Sw и Sh, чтобы найти горизонтальный и вертикальный счет.

Поскольку оно ограничено, оно другое. Правильно ли я понимаю, что вы должны использовать ВСЕ прямоугольники, и результат должен быть также прямоугольником? Я так предположу.

В таком случае у вас не так много вариантов расположения прямоугольников. Есть только столько целых пар, которые дают N при умножении вместе.

В вашем случае я бы попытался найти все возможные такие пары целых чисел (используйте простой цикл FOR) и посмотреть, какая из них ближе всего к квадрату. В цикле FOR обратите внимание, что вам нужно проверять только до sqrt (N), потому что каждая целочисленная пара, которую вы найдете после этого, будет такой же, как уже найденная, только наоборот.

...