У меня есть куча прямоугольных предметов, которые мне нужно упаковать в наименьшее возможное пространство (размеры этого пространства должны быть степенью двойки).
Мне известны различные алгоритмы упаковки, которые максимально упакуют элементы в заданное пространство, однако в этом случае мне нужен алгоритм, чтобы определить, насколько большим должно быть это пространство.
Например, скажем, у меня есть следующие прямоугольники
- 128 * 32
- 128 * 64
- 64 * 32
- 64 * 32
Они могут быть упакованы в пространство 128 * 128
_________________ | 128 * 32 | | ________________ | | 128 * 64 | | | | | | ________________ | | 64 * 32 | 64 * 32 | | _______ | ________ |
Однако, если бы было 160 * 32 и 64 * 64, ему потребовалось бы пространство 256 * 128.
________________________________ | 128 * 32 | 64 * 64 | 64 * 32 | | ________________ | | _______ | | 128 * 64 | | 64 * 32 | | | _______ | _______ | | | | | ________________ | ___ | | 160 * 32 | | | ____________________ | ___________ |
Какие существуют алгоритмы, которые могут упаковать группу прямоугольников и определить требуемый размер для контейнера (до степени 2 и в пределах определенного максимального размера для каждого измерения)?
Ответы:
Быстрое и грязное решение первого прохода - это всегда отличное решение для сравнения, если не считать ничего другого.
Жадное размещение от большого к маленькому.
Поместите самый большой прямоугольник, оставшийся в вашей упакованной области. Если он никуда не помещается, поместите его в место, которое расширяет область упаковки как можно меньше. Повторяйте, пока не закончите с наименьшим прямоугольником.
Это совсем не идеально, но это просто и хорошая базовая линия. Он по-прежнему будет отлично упаковывать ваш оригинальный пример и даст вам эквивалентный ответ и для второго.
источник
См. Эту страницу проекта ARC для обзора решений, есть компромисс между сложностью / временем реализации и оптимальностью, но есть широкий выбор алгоритмов на выбор.
Вот выдержка из алгоритмов:
Алгоритм
уменьшения первой аппроксимации (FFDH) FFDH упаковывает следующий элемент R (без увеличения высоты) на первый уровень, в который входит R. Если ни один уровень не может вместить R, создается новый уровень.
Временная сложность FFDH: O (n · log n).
Коэффициент аппроксимации: FFDH (I) <= (17/10) · OPT (I) +1; асимптотическая граница 17/10 плотная.
Алгоритм
убывающей высоты при следующей аппроксимации (NFDH) NFDH упаковывает следующий элемент R (без увеличения высоты) на текущий уровень, если R соответствует. В противном случае текущий уровень «закрыт» и создается новый уровень.
Временная сложность: O (n · log n).
Коэффициент приближения: NFDH (I) <= 2 · OPT (I) +1; асимптотическая граница 2 жесткая.
Алгоритм
уменьшения наилучшей посадки по высоте (BFDH) BFDH упаковывает следующий элемент R (без увеличения высоты) на уровне среди тех, которые могут вместить R, для которых остаточное горизонтальное пространство является минимальным. Если ни один уровень не может вместить R, создается новый уровень.
Алгоритм снизу-слева (BL)
BL элементов первого порядка по не увеличивающейся ширине. BL упаковывает следующий элемент как можно ближе ко дну, а затем как можно ближе к левому краю, чтобы он мог не перекрываться с каким-либо упакованным элементом. Обратите внимание, что BL не является алгоритмом упаковки, ориентированным на уровень.
Временная сложность: O (n ^ 2).
Коэффициент приближения: BL (I) <= 3 · OPT (I).
Алгоритм Бейкера Up-Down (UD)
UD использует комбинацию BL и обобщение NFDH. Ширина полосы и предметов нормализуются, так что полоса имеет единичную ширину. UD упорядочивает элементы по не увеличивающейся ширине, а затем разделяет элементы на пять групп, каждая из которых имеет ширину в диапазоне (1/2, 1], (1 / 3,1 / 2], (1 / 4,1 / 3 ], (1 / 5,1 / 4], (0,1 / 5]. Полоса также разделена на пять областей R1, ..., R5. В основном, некоторые элементы ширины в диапазоне (1 / i + 1, 1 / i], для 1 <= i <= 4 упакованы в область Ri с помощью BL. Поскольку BL оставляет пространство с увеличивающейся шириной сверху вниз с правой стороны полосы, UD использует это преимущество первым упаковка элемента в Rj для j = 1, ..., 4 (по порядку) сверху вниз. Если такого пространства нет, элемент упаковывается в Ri с помощью BL. Наконец, элементы размером не более 1/5 упакованы в пространства в R1, ..., R4 (обобщенным) алгоритмом NFDH.
Коэффициент аппроксимации: UD (I) <= (5/4) · OPT (I) + (53/8) H, где H - максимальная высота предметов; асимптотическая граница 5/4 плотная.
Алгоритм обратной подгонки (RF)
RF также нормализует ширину полосы и элементов так, чтобы полоса имела единичную ширину. RF сначала укладывает все элементы шириной больше 1/2. Остальные предметы сортируются по не увеличивающейся высоте и будут упакованы выше высоты H0, достигнутой теми, кто больше 1/2. Затем РФ повторяет следующий процесс. Грубо говоря, RF упаковывает предметы слева направо так, чтобы их дно было вдоль линии высоты H0, пока не осталось места. Затем упаковывает предметы справа налево и сверху вниз (так называемый обратный уровень), пока общая ширина не станет как минимум 1/2. Затем обратный уровень падает до тех пор, пока (по крайней мере) один из них не коснется какого-либо предмета ниже. Раскрытие как-то повторяется.
Коэффициент аппроксимации: RF (I) <= 2 · OPT (I).
Алгоритм
Стейнберга Алгоритм Стейнберга, обозначенный в статье буквой M, оценивает верхнюю границу высоты H, необходимую для упаковки всех предметов, так, чтобы было доказано, что входные элементы могут быть упакованы в прямоугольник ширины W и высоты H. Затем они определить семь процедур (с семью условиями), каждая из которых разделит проблему на две меньшие и рекурсивно решит их. Было показано, что любая решаемая задача удовлетворяет одному из семи условий.
Коэффициент аппроксимации: M (I) <= 2 · OPT (I).
Алгоритм Split-Fit (SF) SF делит элементы на две группы: L1 с шириной больше 1/2 и L2 не более 1/2. Все предметы L1 сначала упакованы FFDH. Затем они располагаются так, чтобы все элементы с шириной более 2/3 были ниже элементов с шириной не более 2/3. Это создает прямоугольник R пространства с шириной 1/3. Остальные предметы в L2 затем упаковываются в R, а пространство над теми, которые упакованы в L1, используют FFDH. Уровни, созданные в R, считаются ниже уровней, созданных выше упаковки L1.
Коэффициент приближения: SF (I) <= (3/2) · OPT (I) + 2; асимптотическая граница 3/2 плотная.
Алгоритм
Слеатора Алгоритм Слеатора состоит из четырех шагов:
Все элементы шириной более 1/2 упакованы друг на друга в нижней части полосы. Предположим, что h0 - высота результирующей упаковки. Вся последующая упаковка будет происходить выше h0.
Остальные предметы упорядочены по не увеличивающейся высоте. Уровень предметов упаковывается (в порядке увеличения высоты) слева направо по линии высоты h0.
Затем в середине рисуется вертикальная линия, чтобы разрезать полосу на две равные половины (обратите внимание, что эта линия может разрезать предмет, который частично упакован в правой половине). Нарисуйте два горизонтальных отрезка длиной одну половину, один поперек левой половины (называемый левой базовой линией) и один поперек правой половины (называемой правой базовой линией) как можно ниже, чтобы две линии не пересекали какой-либо элемент.
Выберите левую или правую базовую линию, которая имеет меньшую высоту, и упакуйте уровень предметов в соответствующую половину полосы, пока следующий предмет не станет слишком широким.
Формируется новая базовая линия, и шаг (4) повторяется на нижней базовой линии, пока все элементы не будут упакованы.
Временная сложность: O (n · log n).
Коэффициент аппроксимации алгоритма Слеатора составляет 2,5, что является жестким.
источник
Посмотрите на проблемы с упаковкой . Я думаю, что ваша подпадает под "2D упаковка бен". Вы должны быть в состоянии многому научиться из решений этой и других проблем упаковки.
Также см .: Упаковка прямоугольных данных изображения в квадратную текстуру.
источник
Существует обширная литература по этой проблеме. Хорошая жадная эвристика заключается в размещении прямоугольников от наибольшей области до наименьшей в первой доступной позиции по направлению к нижней и левой части контейнера. Подумайте о гравитации, притягивающей все предметы к левому нижнему углу. Для описания этого Google "Chazelle внизу слева упаковки".
Для оптимальных решений современные методы могут упаковать более 20 прямоугольников за несколько секунд. У Хуанга есть алгоритм, который отделяет проблему нахождения наименьшего ограничивающего прямоугольника от задачи определения, может ли набор прямоугольника поместиться в ограничивающий прямоугольник определенного размера. Вы даете его программе набор прямоугольников, и он сообщает вам наименьшую ограничивающую рамку, необходимую для их упаковки.
В вашем случае ваш внешний цикл должен повторяться от наименьшего возможного ограничивающего прямоугольника вверх (ширина и высота последовательно увеличиваются на степени двух). Для каждого из этих ограничивающих прямоугольников проверьте, можете ли вы найти упаковку для ваших прямоугольников. Вы получите кучу ответов «нет», вплоть до первого ответа «да», который гарантированно будет оптимальным решением.
Для внутреннего цикла вашего алгоритма - того, который отвечает «да» или «нет» ограничительной рамке определенного размера, я бы посмотрел ссылку на Хуан и просто реализовал его алгоритм. Он включает в себя множество оптимизаций поверх базового алгоритма, но вам действительно нужно только основное мясо и картофель. Поскольку вы хотите обрабатывать повороты, в каждой точке ветвления во время поиска просто попробуйте оба поворота и возврат, когда оба поворота не приводят к решению.
источник
Я вполне уверен, что это сложная задача для NP , поэтому для оптимального решения вам придется реализовать алгоритм обратного отслеживания, который пробует каждую возможную комбинацию.
Хорошая новость заключается в том, что из-за необходимости упаковать двухмерные прямоугольники в ограниченное двухмерное пространство вы можете сократить множество возможностей на ранних этапах, так что это может быть не так уж плохо.
источник
Что вам нужно, это на https://github.com/nothings/stb/blob/master/stb_rect_pack.h
образец:
источник
Общее решение нетривиально (математика говорит о том, что совершенно невозможно).
Обычно люди используют генетический алгоритм, чтобы попробовать возможные комбинации, но вы можете сделать это достаточно хорошо, просто поместив сначала самую большую фигуру, а затем пробуя разные места для следующий по величине и так далее.
источник