Algoritmo per "guarire" più rettangoli in un numero minore di rettangoli?


13

inserisci qui la descrizione dell'immagine

Supponiamo che io abbia una griglia di rettangoli di forme e colori diversi e che voglio ridurre (ragionevolmente vicino all'ottimale va bene, non è necessario l'ottimale) il numero di rettangoli per rappresentare lo stesso layout di colori.

L'immagine sopra è un caso molto semplificato e lo spazio bianco tra i rettangoli è solo per la visualizzazione: sarebbero effettivamente ben confezionati.

Qual è un nome di approccio o algoritmo (felice di google) che può aiutarmi a farlo?


3
Puoi dirci un po 'da dove provengono questi rettangoli? Tendono ad allinearsi (approssimativamente) con qualsiasi griglia sottostante, o condividere alcuni blocchi comuni o qualche rettangolo "atom" più piccolo? Possono essere ruotati? Questo sembra il tipo di problema che può essere molto spinoso nel caso più generale, ma può essere molto più semplice se possiamo sfruttare alcuni vincoli o elementi comuni nel tuo particolare scenario.
DMGregory

C'è una griglia sottostante di quadrati (come una scacchiera) e ogni rettangolo condivide i confini con quei quadrati sottostanti. cioè puoi usare un numero intero per descrivere in alto / in basso / a sinistra / a destra di ogni rettangolo. Pertanto non possono essere ruotati in angoli non divisibili per 90 gradi. Anche la griglia NxM è completamente popolata da rettangoli: non ci sono posizioni della griglia scoperte.
xaxxon,

Sto solo cercando di evitare il caso che assomiglia all'esempio sopra (dal punto di vista della colorazione), ma è costituito da una tonnellata di rettangoli 1x1 e li sto elaborando quando riesco a gestire lo spazio in molti meno chiamate.
xaxxon,

Sto indovinando una sorta di "basta iniziare da qualche parte e continuare a provare rettangoli sempre più grandi in una dimensione (diciamo in verticale) fino a quando non si colpisce un bordo di colore, quindi aumentare l'altra dimensione (in orizzontale) fino a quando non si colpisce un bordo. Quindi provare prima in orizzontale Quindi forse prova solo i quadrati (crescendo in diagonale) Ma non sono sicuro che semplicemente selezionare la più grande delle 3 possibilità sopra è l'approccio giusto
xaxxon

È accettabile dividere un rettangolo esistente, se alla fine risulta un minor numero di rettangoli? O l'algoritmo dovrebbe mai fondersi? Inoltre, il conteggio totale è l'unico criterio o preferisci forme più squadrate rispetto a lunghe strisce sottili / rettangoli più grandi rispetto a quelli più piccoli?
DMGregory

Risposte:


15

Innanzitutto, possiamo convertire i rettangoli di origine in celle nella griglia sottostante, per rendere l'input più uniforme. (Rasterizzare efficacemente il problema)

Questo ci consentirà di trovare ottimizzazioni che potrebbero non essere ovvie quando si lavora direttamente con i rettangoli di origine, in particolare quando si tratta di dividere più rettangoli di origine per ricombinarli in modo diverso.

Esempio di conversione di rettangoli in celle della griglia e ritorno

Successivamente possiamo trovare regioni connesse dello stesso colore, usando algoritmi di approfondimento o riempimento di inondazioni. Possiamo considerare isolatamente ogni regione connessa (un poliomino ) - nulla di ciò che facciamo in una regione diversa deve influenzare questa.

In effetti, vogliamo trovare un modo per sezionare questo poliomino in rettangoli (sfortunatamente la maggior parte della letteratura che riesco a trovare riguarda il problema opposto: dissezionare rettangoli in poliomino! Ciò rende difficile la ricerca di indizi ...)

Un metodo semplice è quello di combinare percorsi orizzontali di quadrati adiacenti in lunghi rettangoli sottili. Quindi possiamo confrontare con la riga sopra e combinare se la nostra corsa inizia e finisce coincidono - o quando finiamo ogni corsa / riga, o quando consideriamo ogni cella da aggiungere alla corsa corrente.

Scomposizione di un poliomino in corse orizzontali, quindi fusione verticale

Non so ancora quanto questo metodo si avvicini all'ottimale. Sembra che possa incorrere in un po 'di problemi quando una riga che non ha ancora considerato suggerisce una divisione diversa rispetto alle righe che ha visto finora:

Esempio di un caso con una soluzione a 3 rettangoli, in cui il metodo sopra trova 4

Rilevare quando una corsa / rettangolo è esattamente coperta da corse sopra e sotto, quindi dividerla e fonderle risolverà questo caso particolare, ma non ho esplorato quanto sia generale il problema.

Ho anche esaminato i metodi in cui percorriamo il perimetro del poliomino e lo attraversiamo ogni volta che incontriamo un angolo concavo, ma questo approccio mi sembra più soggetto a errori. Ottenere risultati ottimali sembra richiedere la priorità di taglio che unisce due angoli concavi e le forme che contengono cavità richiedono una gestione speciale, quindi il metodo di scansione delle righe sembra avere il vantaggio della semplicità.

Un altro metodo che sto guardando è quello di prendere la prima corsa trovata nella riga superiore ed estenderla il più lontano possibile. Quindi prendi la prima manche nella prima fila di ciò che rimane ... Questo però si inciampa su forme a T invertite, quindi non è neanche ottimale.

Sento che probabilmente c'è un modo per usare la programmazione dinamica per trovare la divisione ottimale, ma non l'ho ancora trovato.


Grazie per la fantastica risposta! questa soluzione sembra abbastanza veloce da poterla eseguire in alcune direzioni diverse e scegliere quale sembra la migliore - sinistra orizzontale-> destra, destra orizzontale-> sinistra, e poi anche verticale in entrambe le direzioni.
xaxxon,

2
Il problema è che possiamo costruire forme che fuorviano l'algoritmo da ogni direzione di scansione. È probabile che quelli non vengano mostrati in uso reale, ma mi infastidiscono ancora. Penso che ci sia ancora una soluzione semplice ... Qualcosa come notare in ogni corsa, se ci sono angoli concavi sopra di essa a metà corsa. Quindi se una corsa successiva termina esattamente in un punto simile, facciamo un passo indietro attraverso le corse sopra suddividendole verticalmente. Non ho risolto i dettagli completi però.
DMGregory

1
Inoltre, non sono sicuro del motivo per cui è necessario il passaggio di inondazione. Quando passi da un positino a griglia a un rettangolo lungo e magro, puoi semplicemente percorrere l'intera riga o colonna della griglia (in qualsiasi modo stai andando) per creare quei rettangoli 1xN. Non hai mai bisogno di conoscere il poliomino, giusto?
xaxxon,

Hai ragione, il riempimento non è un passaggio necessario. L'ho incluso per giustificare il concentrarsi su una sola regione colorata alla volta nei passaggi successivi, ma è possibile applicare facilmente il metodo di scansione delle righe a più regioni colorate interfogliate. Tuttavia, il metodo basato sul perimetro deve lavorare sul perimetro di una forma alla volta.
DMGregory
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.