Алгоритм "загоєння" декількох прямокутників на меншу кількість прямокутників?


14

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

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

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

Що таке підхід чи алгоритм (радий google), які можуть допомогти мені це зробити?


3
Чи можете ви розповісти нам трохи про те, звідки беруться ці прямокутники? Чи мають вони тенденцію (приблизно) вирівнювати будь-яку базову сітку або поділяти якийсь загальний будівельний блок або якийсь найменший прямокутник «атома»? Чи можна їх обертати? Це виглядає як така проблема, яка може бути дуже кричущою в найбільш загальному випадку, але може стати набагато простішою, якщо ми зможемо використати деякі обмеження чи спільності у вашому конкретному сценарії.
DMGregory

Існує нижня сітка квадратів (як контрольна дошка), і кожен прямокутник поділяє межі з тими основними квадратами. тобто ви можете використовувати ціле число, щоб описати верхній / нижній / лівий / правий кожного прямокутника. Для цього їх не можна обертати на кути, не поділяються на 90 градусів. Також сітка NxM повністю заповнена прямокутниками - немає непокритих позицій сітки.
xaxxon

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

Я здогадуюсь про якийсь "просто почніть десь і продовжуйте пробувати все більші та більші прямокутники в одному вимірі (скажімо вертикально), поки ви не натиснете на кольорову рамку, а потім зростайте інший вимір (по горизонталі), поки не натисніть на межу. Потім спробуйте спочатку горизонтально Тоді, можливо, спробуйте лише квадрати (зростаючи по діагоналі). Але не впевнений, чи правильно вибрати найбільшу з перерахованих вище 3 можливостей - правильний підхід.
xaxxon

Чи прийнятно розділяти наявний прямокутник, якщо в результаті вийде менше прямокутників? Або алгоритм повинен завжди колись зливатися? Також, чи є загальним підрахунком єдиний критерій, чи ви віддаєте перевагу фігурам квадратних розмірів над довгими худими повзунками / більшими прямокутниками над меншими?
DMGregory

Відповіді:


15

По-перше, ми можемо перетворити ваш вихідний прямокутник у комірки вашої базової сітки, щоб зробити введення більш рівномірним. (Ефективно растеризація проблеми)

Це дозволить нам знайти оптимізацію, яка може бути не очевидною при роботі безпосередньо з джерелами прямокутників, особливо коли це стосується розбиття декількох джерел прямокутників для їх комбінації по-різному.

Приклад перетворення прямокутників у комірки сітки та назад

Далі ми можемо знайти з’єднані регіони одного кольору, використовуючи алгоритми глибинного першого пошуку або заливки. Ми можемо розглядати кожну пов'язану область ( поліоміно ) окремо - ніщо, що ми робимо для іншого регіону, не повинно впливати на цю.

Ефективно ми хочемо знайти спосіб розчленувати це поліоміно на прямокутники (на жаль, більшість літератури, яку я можу знайти, стосується протилежної проблеми: розсікання прямокутників на поліміноа! Це ускладнює пошук потенційних клієнтів ...)

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

Розкладаючи поліоміно на горизонтальні прогони, потім зливаючись вертикально

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

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

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

Я також розглядав методи, де ми проходимо по периметру полиомино і вирізаємо в будь-який час, коли ми стикаємося з увігнутим кутом, але такий підхід мені здається більш схильним до помилок. Отримання оптимальних результатів, мабуть, вимагає пріоритетності розрізів, які з'єднуються у двох увігнутих кутах, а форми, що містять дуплі, потребують спеціального керування, тому метод сканування рядків, схоже, має перевагу простоти.

Ще один метод, на який я дивлюся - це зробити перший пробіг, знайдений у верхньому ряду, і продовжити його вниз, наскільки ви можете. Тоді зробіть перший пробіг у верхньому ряду того, що залишилося ... Хоча це спрацьовує на перевернуті форми Т, однак це теж не є оптимальним.

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


Дякую за приголомшливу відповідь! це рішення виглядає досить швидко, щоб я міг виконати його в декількох різних напрямках і вибрати, який з них найкраще - горизонтальний ліворуч-> праворуч, горизонтально праворуч-> ліворуч, а потім вертикально в кожному напрямку.
xaxxon

2
Проблема полягає в тому, що ми можемо побудувати фігури, які вводять в оману алгоритм з кожного напрямку розгортки. Вони, можливо, не виявляться в реальному використанні, але це все одно мене помиляє. Я думаю, що ще є просте виправлення ... Щось на зразок зауваження в кожному прогоні, чи є увігнуті кути над ним у середині пробігу. Потім, якщо наступний пробіг закінчиться в точно такій точці, ми проходимо через прогони вище, розділяючи їх по вертикалі. Я не розбирався з усіма деталями.
DMGregory

1
Крім того, я не впевнений, для чого необхідний крок заливки. Переходячи від сітки позитино до довгого вузького прямокутника, ви можете просто пройти повний ряд або стовпчик сітки (залежно від того, куди ви рухаєтесь), щоб створити ці 1xN прямокутники. Ніколи не потрібно знати полиомино, правда?
xaxxon

Ви маєте рацію, заливка не є необхідним кроком. Я включив його, щоб виправдати зосередження уваги тільки на одній кольоровій області одночасно в наступних кроках, але ви можете легко застосувати метод сканування рядків до переплетених кількох кольорових областей. Метод, що базується на периметрі, повинен працювати по периметру однієї форми за часом.
DMGregory
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.