Подтвердить что ты не робот

Найдите множество самых больших смежных прямоугольников для покрытия нескольких областей

Я работаю над инструментом Quickfort для игры Крепость-гном. Quickfort превращает электронные таблицы в формате csv/xls в ряд команд для Крепости Гномов, чтобы выполнить "план" в игре.

В настоящее время я пытаюсь оптимально решить проблему построения области для выпуска 2.0 этого инструмента.

Рассмотрим следующий "чертеж", который определяет составление команд для двумерной сетки. Каждая ячейка в сетке должна быть выкопана ( "d" ), направляется ( "c" ) или остается незамкнутой ( "." ). В фактическом использовании может присутствовать любое количество отдельных команд построения.

. d . d c c
d d d d c c
. d d d . c
d d d d d c
. d . d d c

Чтобы свести к минимуму количество инструкций, которые нужно отправить в Крепость Гномов, я хотел бы найти набор самых больших смежных прямоугольников, которые могут быть сформированы, чтобы полностью покрыть или "заговорить" все ячейки, способные к размножению. Чтобы быть действительными, все ячейки прямоугольника должны содержать одну и ту же команду.

Это более быстрый подход, чем Quickfort 1.0: построение каждой ячейки по отдельности в виде прямоугольника 1x1. Это видео показывает разницу в производительности между двумя версиями.

В приведенном выше проекте решение выглядит следующим образом:

. 9 . 0 3 2
8 1 1 1 3 2
. 1 1 1 . 2
7 1 1 1 4 2
. 6 . 5 4 2

Каждый прямоугольник с одинаковым номером обозначает смежный прямоугольник. Самые большие прямоугольники имеют приоритет над меньшими прямоугольниками, которые также могут быть сформированы в их областях. Порядок нумерации/прямоугольников не имеет значения.

Мой текущий подход является итеративным. На каждой итерации я строю список из самых больших прямоугольников, которые могут быть сформированы из каждой из сетчатых ячеек, распространяющихся во всех четырех направлениях от ячейки. После сортировки самого большого списка сначала я начинаю с самого большого найденного прямоугольника, отмечаю его базовые ячейки как "построенные" и записывая прямоугольник в списке. Перед построением каждого прямоугольника его базовые ячейки проверяются, чтобы убедиться, что они еще не построены (перекрытие предыдущего графика). Затем мы начинаем снова, находим самые большие оставшиеся прямоугольники, которые могут быть сформированы и построены, пока все ячейки не будут отложены как часть некоторого прямоугольника.

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

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

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

. 3 . 5 6 8
1 3 4 5 6 8
. 3 4 5 . 8
2 3 4 5 7 8
. 3 . 5 7 8

Эта вторая цель фактически представляет собой более оптимальное решение проблемы, поскольку меньшее количество прямоугольников обычно означает меньшее количество команд, отправленных в Крепость Гномов. Однако этот подход мне кажется ближе к NP-Hard, основанный на моих ограниченных математических знаниях.

Посмотрите видео, если хотите лучше понять общую стратегию; Я не рассматривал другие аспекты процесса Quickfort, такие как поиск кратчайшего пути курсора, который отображает все прямоугольники. Возможно, существует решение этой проблемы, которая когерентно объединяет эти множественные стратегии.

Помощь любой формы будет оценена.

4b9b3361

Ответ 1

Я нашел статью Быстрые алгоритмы для разбиения простых прямоугольных многоугольников из Сан-Юань Ву и Сартадж Сахни, которые могут вас заинтересовать. В вашем примере область с символом 'd' образует прямолинейный многоугольник, а также области с 'c' и '.'. Эта статья содержит алгоритмы для простых простых прямолинейных полигонов без отверстий.

Если многоугольник включает в себя отверстия, существуют алгоритмы, работающие с временем O (n ^ 3/2 log n), как JM Keil в статье Разложение многоугольника на стр. 11.

Если минимизировать общую длину сегментов линии, введенных в процессе разбиения, является другим критерием оптимизации, проблема становится NP-полной, если многоугольник содержит отверстия (стр. 12). Для этих задач существуют алгоритмы аппроксимации (в документе упоминаются работы с такими алгоритмами). Если многоугольник не содержит дырок, существует алгоритм времени O (n ^ 4).

Ответ 2

На самом деле это не ответ, но используя наивный поиск, вы можете получить

. 1 . 2 3 3
4 1 5 2 3 3
. 1 5 2 . 6
7 1 5 2 8 6
. 1 . 2 8 6

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

В некоторых случаях это, вероятно, очень неэффективно, но это быстро, поскольку вам не нужно что-то пересчитывать.

Ответ 4

На мой взгляд, все решения, которые находят набор прямоугольников, которые покрывают исходную область, являются правильными. Найти меньший набор прямоугольников лучше, потому что он сжимает/работает лучше.

Поэтому я бы не советовал найти оптимальное решение. (Я бы предположил, что это тоже NP-hard).

Для более быстрого запуска вы можете сначала разбивать матрицу на группы из 4 ячеек и пытаться объединить их, если они одинаковы. После этого вы можете объединить группы из 4 групп, если они одинаковы. И сделайте это рекурсивно, если вы закончите.

Это не найдет оптимальное решение, но будет очень быстрым. Если ваши матрицы большие, с большими смежными областями, разница с оптимальной не будет такой большой.