Слияние и разделение перекрывающихся прямоугольников для создания неперекрывающихся

Я ищу алгоритм следующим образом:

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

На первый взгляд это кажется достаточно простым, но оказывается сложным (по крайней мере, для эффективного выполнения).

Есть ли какие-то известные методы для этого/идей/указателей?

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


comment
Вы имеете в виду взять объединение прямоугольников и разделить его на прямоугольные области? Или объединение исходных строк также должно быть выражено в выводе? Другими словами, если у меня есть два прямоугольника 10x20, которые граничат друг с другом, могу ли я вывести один квадрат 20x20? Или мне всегда нужно иметь как минимум два выхода, если у меня есть два входа?   -  person tfinniga    schedule 03.05.2010
comment
Единственное требование к (объединению) выходного набора состоит в том, чтобы занимать ту же площадь, что и (объединение) входного набора, и состоять из непересекающихся прямоугольников. Желательно, чтобы он тоже был минимальным: включайте как можно меньше прямоугольников. Так что да, в этом случае вам лучше выплюнуть один прямоугольник.   -  person uj2    schedule 04.05.2010
comment
Какой язык программирования вы используете?   -  person tfinniga    schedule 06.05.2010
comment
Для тех, кто появится в будущем - " title="алгоритм поиска наименьшего количества прямоугольников для покрытия набора прямоугольников без"> stackoverflow.com/questions/5919298/ является дубликатом этого с оптимальным и эффективным решением в ответах.   -  person Julian    schedule 03.10.2020


Ответы (2)


Я думаю, что что-то, основанное на алгоритме линейной развертки, сработает:

  • Отсортируйте все минимальные и максимальные координаты x ваших прямоугольников в массив, как события "начало-прямоугольник" и "конец-прямоугольник"
  • Пройдитесь по массиву, добавляя каждый новый встречающийся прямоугольник (начальное событие) в текущий набор
  • Одновременно поддерживайте набор «неперекрывающихся прямоугольников», которые будут вашим выходным набором.
  • Каждый раз, когда вы сталкиваетесь с новым прямоугольником, вы можете проверить, полностью ли он уже содержится в текущем/выходном наборе (достаточно простого сравнения y-координат)
  • Если это не так, добавьте новый прямоугольник в выходной набор с y-координатами, установленными для той части нового прямоугольника, которая еще не покрыта.
  • Каждый раз, когда вы сталкиваетесь с конечным событием прямоугольника, останавливайте любые прямоугольники в выходном наборе, которые больше ничего не покрывают.

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

person tzaman    schedule 02.05.2010
comment
Этот комментарий подтолкнул меня к некоторым хорошим идеям, я прошел большую часть реализации, но у меня возникли проблемы с некоторыми крайними случаями. Можете ли вы уточнить случай конечного события? Что означает для прямоугольника «больше ничего не покрывать»? - person schellsan; 19.04.2012
comment
@schellsan - представьте себе вертикальную линию, проходящую слева направо по входному набору (от -x до +x). Когда вы попадаете в начало любого входного прямоугольника, вам нужно создать новый выходной прямоугольник, чтобы покрыть его, если он уже полностью не закрыт одним из ваших существующих выходных прямоугольников. Когда вы достигаете конца любого входного прямоугольника, если в этом пространстве (координат y) нет других входных прямоугольников, вам нужно закончить какой-то выходной прямоугольник (и, возможно, создать несколько новых, в зависимости от входной конфигурации). - person tzaman; 20.04.2012
comment
Да, это то, что я понял. Спасибо за помощь! - person schellsan; 20.04.2012

Итак, если бы я пытался это сделать, первое, что я бы сделал, это придумал бы единое пространство сетки. Найдите все уникальные координаты x и y и создайте сопоставление с индексным пространством. Итак, если у вас есть значения x {-1, 1,5, 3,1}, сопоставьте их с {0, 1, 2} и аналогично для y. Тогда каждый прямоугольник можно точно представить с помощью этих упакованных целочисленных координат.

Затем я выделял битвектор или что-то, что покрывает всю сетку, и растрировал ваши прямоугольники в сетке. Хорошая вещь в сетке заключается в том, что с ней действительно легко работать, и, ограничивая ее уникальными координатами x и y, она минимальна и точна.

Один из способов найти довольно быстрое решение — просто выгрузить каждый «пиксель» вашей сетки. Прогнать их обратно через отображение, и все готово. Если вы ищете более оптимальное количество прямоугольников, то у вас есть своего рода проблема поиска.

Посмотрим на 4 соседних пикселя, небольшой квадрат 2х2. Когда я пишу подобные алгоритмы, я обычно думаю о вершинах, ребрах и гранях. Итак, это грани вокруг вершины. Если 3 из них включены, а 1 выключен, то у вас вогнутый угол. Это единственный неправильный случай. Например, если у меня нет вогнутых углов, я просто беру экстенты и выгружаю все это как один прямоугольник. Для каждого вогнутого угла вам нужно решить, следует ли разделить его по горизонтали, по вертикали или по обоим направлениям. Я думаю о разделении как о маркировке ребер, чтобы не пересекать их при поиске экстентов. Вы также можете сделать это, раскрашивая наборы, как вам будет проще.

Вогнутые углы и направления их разделения - это ваше пространство поиска. Вы можете использовать любой алгоритм оптимизации, какой захотите. Branch/bound может работать хорошо. Бьюсь об заклад, вы могли бы найти простую эвристику, которая хорошо работает (например, если есть еще один вогнутый угол прямо напротив того, который вы рассматриваете, всегда разделяйте в этом направлении. В противном случае разделяйте в более коротком направлении). Ты можешь просто стать жадным. Или вы можете просто разделить каждую вогнутую вершину в обоих направлениях, что, как правило, даст вам меньше прямоугольников, чем вывод каждого «пикселя» в виде прямоугольника, и это будет довольно просто.

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

person tfinniga    schedule 03.05.2010