Алгоритм «исцеления» нескольких прямоугольников в меньшее количество прямоугольников?

14

введите описание изображения здесь

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

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

Что такое подход или название алгоритма (рад Google), который может помочь мне сделать это?

xaxxon
источник
3
Не могли бы вы рассказать нам немного о происхождении этих прямоугольников? Имеют ли они тенденцию (примерно) выравниваться с какой-либо базовой сеткой или имеют общий строительный блок или какой-то наименьший прямоугольник «атом»? Могут ли они вращаться? Это похоже на проблему, которая может быть очень сложной в самом общем случае, но может стать намного проще, если мы сможем использовать некоторые ограничения или общие черты в вашем конкретном сценарии.
DMGregory
Существует базовая сетка квадратов (например, шахматная доска), и каждый прямоугольник разделяет границы с этими базовыми квадратами. то есть вы можете использовать целое число для описания верха / низа / слева / справа каждого прямоугольника. Поэтому их нельзя поворачивать на углы, не делимые на 90 градусов. Также сетка NxM полностью заполнена прямоугольниками - нет открытых позиций сетки.
xaxxon
Я просто пытаюсь избежать случая, который выглядит как пример выше (с точки зрения окраски), но он состоит из тонны прямоугольников 1x1, и я обрабатываю каждый из них, когда могу обрабатывать пространство во многих меньше звонков.
xaxxon
Я предполагаю что-то вроде «просто начните где-нибудь и продолжайте пробовать все больше и больше прямоугольников в одном измерении (скажем, по вертикали), пока не достигнете цветовой границы, затем увеличивайте другое измерение (по горизонтали), пока не достигнете границы. Затем сначала попробуйте по горизонтали Тогда, может быть, попробуйте только квадраты (растущие по диагонали). Но не уверен, что правильный выбор самого большого из этих трех вариантов - правильный подход.
xaxxon
Допустимо ли разделять существующий прямоугольник, если в результате получается меньше прямоугольников? Или алгоритм должен только когда-либо слиться? Кроме того, является ли общий счет единственным критерием, или вы предпочитаете квадратные формы длинным узким полосам / более крупным прямоугольникам, а не меньшим?
DMGregory

Ответы:

15

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

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

Пример преобразования прямоугольников в ячейки сетки и обратно

Затем мы можем найти связанные области одного цвета, используя алгоритмы поиска в глубину или заливки. Мы можем рассматривать каждый связанный регион ( полиомино ) изолированно - ничто из того, что мы делаем с другим регионом, не должно влиять на этот регион.

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

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

Разложение полиомино на горизонтальные участки с последующим слиянием по вертикали

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

Пример случая с 3-прямоугольным решением, где вышеуказанный метод находит 4

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

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

Еще один метод, который я рассматриваю, заключается в том, чтобы взять первый прогон, найденный в верхнем ряду, и расширить его как можно дальше. Затем сделайте первый прогон в верхнем ряду того, что осталось ... Это срабатывает на перевернутых Т-формах, так что это тоже не оптимально.

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

ДМГригорий
источник
Спасибо за отличный ответ! это решение выглядит достаточно быстрым, чтобы я мог запустить его в нескольких разных направлениях и выбрать наиболее подходящее - горизонтальное левое -> правое, горизонтальное правое -> левое, а затем также вертикальное в каждом направлении.
xaxxon
2
Проблема в том, что мы можем создавать фигуры, которые будут вводить алгоритм в заблуждение со всех направлений развертки. Они вряд ли появятся в реальном использовании, но это все еще меня беспокоит. Я думаю, что есть простое исправление ... Что-то вроде того, чтобы замечать в каждом прогоне, есть ли в середине вогнутые углы над ним. Затем, если последующий прогон заканчивается именно в этой точке, мы возвращаемся через прогоны выше, разбивая их по вертикали. Я не разобрался в полной детали, хотя.
DMGregory
1
Кроме того, я не уверен, почему необходим шаг заливки. Переходя от позиции сетки к длинному тощему прямоугольнику, вы можете просто пройти весь ряд или столбец сетки (в зависимости от того, как вы собираетесь), чтобы создать эти прямоугольники 1xN. Не нужно когда-либо знать полиомино, верно?
xaxxon
Вы правы, наводнение не является необходимым шагом. Я включил его, чтобы оправдать фокусировку только на одной цветной области за раз в последующих шагах, но вы могли легко применить метод сканирования строк к чередующимся цветным областям. Однако метод, основанный на периметре, должен работать по периметру одной фигуры за раз.
DMGregory