Упаковочные прямоугольники для компактного представления
Я ищу указатели для решения следующей проблемы: у меня есть набор прямоугольников, высота которых также известна, а также x-позиций, и я хочу упаковать их в более компактную форму. С небольшим рисунком (где все прямоугольники имеют одинаковую ширину, но ширина может варьироваться в реальной жизни), я бы хотел вместо.
-r1-
-r2--
-r3--
-r4-
-r5--
что-то вроде.
-r1- -r3--
-r2-- -r4-
-r5--
Все советы будут оценены. Я не обязательно ищу "лучшее" решение.
6 ответов
Ваша проблема - более простой вариант, но вы можете получить несколько советов, читающих об эвристике, разработанной для проблемы "binpacking". Об этом много написано, но эта страница - хорошее начало.
У Topcoder был конкурс для решения 3D-версии этой проблемы. Победитель обсудил свой подход здесь, это может быть интересным для вас.
Все ли прямоугольники одинаковой высоты? Если они есть, и проблема состоит только в том, в какую строку помещать каждый прямоугольник, то проблема сводится к серии ограничений по всем парам прямоугольников (X,Y) формы "прямоугольник X не может находиться в той же строке, что и прямоугольник Y", когда прямоугольник X перекрывается в направлении х с прямоугольником Y.
"Жадный" алгоритм для этого сортирует прямоугольники слева направо, а затем назначает каждый прямоугольник по очереди строке с наименьшим номером, в которую он помещается. Поскольку прямоугольники обрабатываются слева направо, нужно только беспокоиться о том, будет ли левый край текущего прямоугольника перекрывать какие-либо другие прямоугольники, что несколько упрощает алгоритм обнаружения перекрытия.
Я не могу доказать, что это дает оптимальное решение, но, с другой стороны, не может придумать и никаких контрпримеров наугад. Кто-нибудь?
Что-то вроде этого?
- Сортировать вашу коллекцию прямоугольников по X-позиции
написать метод, который проверяет, какие прямоугольники присутствуют на определенном интервале оси X
Collection<Rectangle> overlaps (int startx, int endx, Collection<Rectangle> rects){ ... }
перебрать коллекцию прямоугольников
Collection<Rectangle> toDraw; Collection<Rectangle> drawn; foreach (Rectangle r in toDraw){ Collection<Rectangle> overlapping = overlaps (r.x, r.x+r.width, drawn); int y = 0; foreach(Rectangle overlapRect in overlapping){ y += overlapRect.height; } drawRectangle(y, Rectangle); drawn.add(r); }
Поместите тетрис-подобную игру на свой сайт. Генерируйте падающие блоки и размер игровой площадки на основе ваших параметров. Награда очков игрокам основана на компактности (меньше свободного места = больше очков) их дизайна. Получите посетителей вашего сайта, чтобы выполнить работу за вас.
Я работал над такой проблемой раньше. Наиболее интуитивно понятная картина, вероятно, та, где большие прямоугольники находятся снизу, а более мелкие - сверху, что-то вроде складывания их в контейнер и встряхивания, так что тяжелые падают на дно. Поэтому для этого сначала отсортируйте массив в порядке уменьшения площади (или ширины) - сначала мы обработаем большие элементы и создадим изображение с нуля.
Теперь проблема состоит в том, чтобы назначить y-координаты набору прямоугольников, чьи x-координаты даны, если я вас правильно понимаю.
Итерируйте по вашему массиву прямоугольников. Для каждого прямоугольника инициализируйте y-координату прямоугольника равным 0. Затем зацикливайте, увеличивая y-координату этого прямоугольника, пока он не пересекается ни с одним из ранее размещенных прямоугольников (вам необходимо отслеживать, какие прямоугольники были ранее размещены). Подтвердите координату y, которую вы только что нашли, и продолжите обработку следующего прямоугольника.