Algoritmo para "curar" vários retângulos em um número menor de retângulos?

13

insira a descrição da imagem aqui

Digamos que eu tenha uma grade de retângulos de diferentes formas e cores e que eu queira reduzir (razoavelmente próximo de ótimo é bom, ideal não é necessário) o número de retângulos para representar o mesmo layout de cores.

A imagem acima é um caso muito simplificado e o espaço em branco entre os retângulos é apenas para visualização - eles seriam realmente compactados.

O que é um nome de abordagem ou algoritmo (feliz pelo google) que pode me ajudar a fazer isso?

xaxxon
fonte
3
Você pode nos contar um pouco sobre a origem desses retângulos? Eles tendem a (aproximadamente) se alinhar com qualquer grade subjacente, ou compartilhar algum bloco de construção comum ou algum menor retângulo "átomo"? Eles podem ser girados? Parece o tipo de problema que pode ser muito difícil no caso mais geral, mas pode ficar muito mais fácil se pudermos explorar algumas restrições ou pontos comuns em seu cenário específico.
DMGregory
Há uma grade de quadrados subjacente (como um tabuleiro de damas) e cada retângulo está compartilhando limites com esses quadrados subjacentes. ou seja, você pode usar um número inteiro para descrever a parte superior / inferior / esquerda / direita de cada retângulo. Portanto, eles não podem ser girados em ângulos não divisíveis em 90 graus. Além disso, a grade do NxM é totalmente preenchida com retângulos - não há posições de grade descobertas.
Xaxxon
Estou apenas tentando evitar o caso que se parece com o exemplo acima (de uma perspectiva de coloração), mas é composto por uma tonelada de retângulos 1x1 e estou processando cada um deles quando posso lidar com o espaço em muitos menos chamadas.
Xaxxon 08/09/19
Eu estou supondo que algum tipo de "apenas comece em algum lugar e continue tentando retângulos cada vez maiores em uma dimensão (digamos, verticalmente) até atingir uma borda colorida, depois aumente a outra dimensão (horizontalmente) até atingir uma borda. Em seguida, tente horizontalmente primeiro . Então, talvez tente única quadrados (o número cresce na diagonal) Mas não tenho certeza se simplesmente selecionando o maior dos acima de 3 possibilidades é a abordagem correta..
xaxxon
É aceitável dividir um retângulo existente, se resultar em menos retângulos no final? Ou o algoritmo deve apenas se fundir? Além disso, a contagem total é o único critério, ou você prefere formas mais quadradas do que lascas finas longas / retângulos maiores que os menores?
DMGregory

Respostas:

15

Primeiro, podemos converter os retângulos de origem em células na grade subjacente, para tornar a entrada mais uniforme. (Efetivamente rasterizando o problema)

Isso nos permitirá encontrar otimizações que podem não ser óbvias ao trabalhar diretamente com os retângulos de origem - principalmente quando se trata de dividir vários retângulos de origem para recombiná-los de maneira diferente.

Exemplo de conversão de retângulos em células da grade e vice-versa

Em seguida, podemos encontrar regiões conectadas da mesma cor, usando algoritmos de profundidade de primeira pesquisa ou preenchimento de inundação. Podemos considerar cada região conectada (um poliomino ) isoladamente - nada do que fazemos em uma região diferente precisa influenciar essa região.

Efetivamente, queremos encontrar uma maneira de dissecar esse poliomino em retângulos (infelizmente, a maior parte da literatura que encontro é sobre o problema oposto: dissecar retângulos em poliamino! Isso dificulta a pesquisa de leads ...)

Um método simples é combinar trechos horizontais de quadrados adjacentes em retângulos finos e longos. Em seguida, podemos comparar com a linha acima e combiná-la se nossa execução começar e terminar de acordo - ou ao finalizarmos cada execução / linha ou quando considerarmos que cada célula será adicionada à execução atual.

Decompondo um polyomino em execuções horizontais e depois mesclando verticalmente

Ainda não sei até que ponto esse método chega ao ideal. Parece que pode ter problemas quando uma linha que ainda não considerou sugere uma divisão diferente das linhas vistas até agora:

Exemplo de um caso com uma solução de 3 retângulos, em que o método acima encontra 4

Detectar quando uma corrida / retângulo é exatamente coberta por corridas acima e abaixo, depois dividi-las e mesclá-las resolverá esse caso em particular, mas não explorei o quão geral é o problema.

Também examinei métodos nos quais percorremos o perímetro do polyomino e atravessamos toda vez que encontramos um canto côncavo, mas essa abordagem me parece mais propensa a erros. A obtenção de resultados ideais parece exigir cortes priorizados que se juntam a dois cantos côncavos, e as formas que contêm cavidades precisam de tratamento especial; portanto, o método de varredura de linhas parece ter a vantagem da simplicidade.

Outro método que estou procurando é fazer a primeira execução encontrada na linha superior e estendê-la o mais longe possível. Em seguida, faça a primeira corrida na linha superior do que resta ... Isso ocorre em formas T invertidas, portanto, também não é o ideal.

Sinto que provavelmente existe uma maneira de usar a programação dinâmica para encontrar a divisão ideal, mas ainda não a encontrei.

DMGregory
fonte
Obrigado pela resposta incrível! essa solução parece rápida o suficiente para que eu possa executá-la em algumas direções diferentes e escolher qual delas parece melhor - horizontal esquerda-> direita, horizontal direita-> esquerda e, em seguida, vertical também.
Xaxxon 9/09/16
2
O problema é que podemos construir formas que enganem o algoritmo de todas as direções da varredura. Talvez não seja provável que eles apareçam em uso real, mas isso ainda me incomoda. Acho que ainda existe uma solução simples ... Algo como anotar em cada corrida, se há cantos côncavos acima dela no meio da corrida. Então, se uma execução subsequente terminar exatamente nesse ponto, voltaremos pelas execuções acima, dividindo-as verticalmente. Ainda não resolvi os detalhes completos.
DMGregory
1
Além disso, não sei por que a etapa de preenchimento é necessária. Ao passar de um positino da grade para um longo retângulo fino, você pode simplesmente percorrer a linha ou coluna completa da grade (para onde estiver indo) para criar esses retângulos 1xN. Não há necessidade de conhecer o polyomino, certo?
Xaxxon 9/09/16
Você está certo, o preenchimento de inundação não é uma etapa necessária. Incluí-o para justificar o foco em apenas uma região colorida por vez nas etapas subseqüentes, mas você pode aplicar facilmente o método de varredura de linha a várias regiões coloridas intercaladas. O método baseado no perímetro precisa trabalhar no perímetro de uma forma por vez.
DMGregory