Organizando retângulos arbitrários para preencher um espaço


26

Esses retângulos podem preencher um espaço retangular?

Dado um monte de retângulos, você será perguntado se eles podem ou não ser organizados para preencher um espaço retangular.

Especificações

Dado um monte de m x nretângulos arbitrários ; 0 <= m, n <= 1000, determine se é possível ou não organizá-los para que cubram exatamente uma área retangular, sem furos ou sobreposições. Os retângulos não podem ser girados e cada retângulo pode ser colocado apenas uma vez.

Entrada

A entrada para isso é muito flexível, desde que a entrada forneça algum tipo de lista de dimensões com 2 espaços. Por exemplo, ambos os seguintes são válidos:

Separado pelo espaço, retorno

1 2
1 5
4 5
3 6

Lista de dimensões

[[1, 2], [1, 5], [4, 5], [3, 6]]

Saída

Qualquer tipo de valor verdadeiro / falso, como verdadeiro / falso, 0/1, T / F, Verdadeiro / Falso etc. Se você usar um método de saída que não seja muito óbvio, especifique na sua resposta.

Exemplos

Caso de teste 1

Entrada:

1 1
1 5
2 6

Saída: true(ou algo semelhante)
Como organizar:

XYYYYY
ZZZZZZ
ZZZZZZ

Caso de teste 2

Entrada:

1 1
2 2

Saída: false(ou algo semelhante)
Explicação: Torna-se óbvio que você não pode organizar dois quadrados de tamanhos diferentes e alinhar suas bordas.

Caso de teste 3

Entrada:

1 1
1 2
1 2
2 1
2 1

Saída: true(ou algo semelhante) Como organizar:

AAB
DEB
DCC

Como o @ETHProductions apontou, para todos os outros casos de teste, você pode continuar combinando retângulos com um comprimento de borda comum até ter apenas um retângulo; portanto, este caso de teste é apenas para quebrar qualquer código que use essa idéia.

Caso de teste 4

Entrada:

3 2
4 1
2 1
4 1
2 1
5 2
3 2
1 4
3 2
2 1
2 1
1 1
5 1

Saída: true(ou algo semelhante)
Como organizar:

AAABBBBEE
AAACCDDDD
FFFFFGGGH
FFFFFGGGH
IIIJJKKLH
IIIMMMMMH

Nota : Você não precisa declarar como organizá-lo, apenas precisa determinar se não pode ser arranjado.

Isso é código de golfe, então a resposta mais curta em bytes vence! Aceitarei a resposta mais curta a partir de 14 de janeiro, mas fique à vontade para enviar respostas depois disso, pois ainda posso dar votos! :)

Feliz golfe!

~ AL

PS Se você souber qual tag deve ser aplicada a esse problema, adicione-a, não faço a menor idéia do que colocar como tag, exceto code-golf.

Edição : seu programa deve ser capaz de processar até 25 retângulos, em no máximo 10 segundos em um computador decente (eu serei bastante flexível com essa regra).

EDIT : Estendi o prazo de aceitação de envio para o último dia do ano, mas duvido que receberei uma resposta até então ...

EDIT : estendi o prazo de aceitação de envio em 2 semanas; portanto, se não houver mais respostas até então, a resposta C atual será aceita! :)


Presumo que cada retângulo de entrada seja usado apenas uma vez?
xnor 21/10

7
Por que existe um prazo? Pode-se dizer que você vai aceitar uma resposta naquela época, mas desafios devem ser abertas indefinidamente :)
Nathan Merrill

4
Os retângulos podem ser girados?
Xnor 21/10

3
Bem, seu problema é um problema de decidibilidade: "esses retângulos orientados podem ser organizados para formar outro retângulo com 0 desperdício", que é um problema NP-completo (Korf, 2003: pdfs.semanticscholar.org/90a5/… ). O algoritmo de Korf é essencialmente uma força bruta com algumas otimizações para eliminar de forma mais eficiente configurações sem solução. Duvido que um golf disso esteja abaixo de 250 caracteres na maioria dos idiomas.
Gabriel Benamy 22/10

1
A rota mais fácil seria determinar se você pode combinar repetidamente dois retângulos da mesma largura ou altura até ter 1 retângulo restante. Esse algoritmo funciona para todos os casos de teste atuais; no entanto, falha em [[1, 2], [2, 1], [1, 1], [1, 2], [2, 1]](que pode ser arranjado ABB ACD EED). Você pode adicionar este caso de teste simples.
ETHproductions

Respostas:


5

C, 1135 1158 1231 1598 bytes

Bem, já passou do prazo estabelecido, mas, como ainda não há respostas, aqui está uma (um pouco longa) em C.

Devoluções:

  • 0 (zero) em caso de falha (não cabe)
  • Matriz de montagem completa em caso de sucesso

Atualizar:

O código original pode ficar preso em algumas matrizes, levando muito mais tempo do que os 10s permitidos. A revisão atual deve concluir todas as matrizes abaixo de 1s. Isso é feito 1) Classificando os retângulos de entrada e 2) pulando os tamanhos repetidos durante o ajuste.

Golfe:

#define R r[i]
#define Z return
#define _(B,D,E) for(int B=E;B<D;B++)
struct{int x,y,u,p;}r[25],*S;int A,M,N,U,V,X,Y;char *P;T(x,y,w,h){_(I,x+w,x)_(J,y+h,y)if(I/U|J/V|P[J*U+I])Z 0;Z 1;}L(x,y,w,h,c){_(I,x+w,x)_(J,y+h,y)P[J*U+I]=c;}F(){int x=0,y;while(++x<A)if(!P[x])break;if(x/A){_(i,V,0)printf("%*.*s\n",U,U,P+i*U);exit(0);}y=x/U;x-=y*U;_(i,N,0)if(!R.u&T(x,y,R.x,R.y))R.u=1,L(x,y,R.x,R.y,'A'+i),F(),R.u=0,L(x,y,R.x,R.y,0);}O(i,y){if(!R.u){if(!T(0,y,R.x,R.y))Z;R.u=1;R.p=0;L(0,y,R.x,R.y,'A'+i);y+=R.y;}if(y-V||F())_(j,N,0)if(j-i&!r[j].u){O(j,y);while(r[j].x-r[j+1].x|r[j].y-r[j+1].y)j++;}R.u=0;L(R.p,(y-=R.y),R.x,R.y,0);}Q(i,x){if(!R.u){if(R.x>U-x)Z;R.u=1;R.p=x;L(x,0,R.x,R.y,'A'+i);x+=R.x;}if(x-U||O(i,1))_(j,N,0)if(j-i&!r[j].u)Q(j,x);L(x-=R.x,0,R.x,R.y,0);R.u=0;}C(int*a,int*b){Z*a-*b?*a-*b:a[1]-b[1];}main(){_(i,25,0)if(++N&scanf("%d%d\n",&R.x,&R.y)-2)break;_(i,N,0){A+=R.x*R.y;if(R.x>X)X=R.x;if(R.y>Y)Y=R.y;}_(i,A+1,1)if(!(A%i)){if(i<Y|A/i<X)continue;M++;S=realloc(S,M*16);S[M-1].y=i;S[M-1].x=A/i;}qsort(S,M,16,C);P=calloc(A+1,1);_(j,M,0){U=S[j].x;V=S[j].y;_(i,N,0)R.u=1,L(0,0,R.x,R.y,'A'+i),Q(i,R.x),R.u=0;}printf("0\n");exit(1);}

UnGolfed:

#define R r[i]
#define Z return
#define _(B,D,E) for(int B=E;B<D;B++)
struct {
    int x,y,u,p;
} r[25],*S;
int A,M,N,U,V,X,Y;
char *P;

test_space(x,y,w,h) {
    _(I,x+w,x)
        _(J,y+h,y)
            if (    I >= U |
                    J >= V |
                    P[J*U+I]) Z 0;
    Z 1;
}
place_rect(x,y,w,h,c){
    _(I,x+w,x)
        _(J,y+h,y)P[J*U+I] = c;
}

fill_rest() {
    int x=0,y;
    while(++x<A) if (!P[x])break;
    if (x>=A) {
        _(i,V,0) printf("%*.*s\n", U,U, P+i*U);
        exit(0);
    }
    y = x / U; x -= y*U;

    _(i,N,0)
        if (!R.u & test_space(x, y, R.x, R.y))
                R.u = 1,
                place_rect(x, y, R.x, R.y, 'A'+i),
                fill_rest(),
                R.u = 0,
                place_rect(x, y, R.x, R.y, 0);

}

fill_y(i,y) {
    if (!R.u) {
        if (!test_space(0, y, R.x, R.y)) Z;
        R.u = 1;
        R.p = 0;
        place_rect(0, y, R.x, R.y, 'A'+i);
        y += R.y;
    }
    if (y == V) fill_rest();
    else _(j,N,0)
        if (j!=i && !r[j].u){ fill_y(j, y);
        while (r[j].x^r[j+1].x||r[j].y^r[j+1].y)j++;
        }
    R.u = 0;
    place_rect(R.p, (y -= R.y), R.x, R.y, 0);
}

fill_x(i,x) {
    if (!R.u) {
        if (R.x > U - x) Z;
        R.u = 1;
        R.p = x;
        place_rect(x, 0, R.x, R.y, 'A'+i);
        x += R.x;
    }
    if (x == U) fill_y(i, 1);
    else
        _(j,N,0)
            if (j!=i && !r[j].u) fill_x(j, x);
    place_rect((x -= R.x), 0, R.x, R.y, 0);
    R.u = 0;
}
C(int*a,int*b) {
    Z *a^*b?*a-*b:a[1]-b[1];
}


main() {
    _(i,25,0)
        if (++N&&scanf("%d %d\n", &R.x, &R.y)!=2) break;
    _(i,N,0){
        A+=R.x*R.y;
        if(R.x>X)X=R.x;
        if(R.y>Y)Y=R.y;
    }
    _(i,A+1,1)
        if (!(A%i)) {
            if (i < Y | A/i < X) continue;
            M++;
            S = realloc(S,M*16);
            S[M-1].y=i;
            S[M-1].x=A/i;
        }
    qsort(S, M, 16,C);
    P = calloc(A + 1,1);
    _(j,M,0){
        U = S[j].x; V = S[j].y;
        _(i,N,0)
            R.u = 1,
            place_rect(0, 0, R.x, R.y, 'A'+i),
            fill_x(i, R.x),
            R.u = 0;
    }
    printf("0\n");
    exit(1);
}

Explicação: Nós temos 6 funções: main, O, Q, F, Le T. T t ESTs para ver se há espaço para o rectângulo em um determinado local. Lfil l é um rectângulo para a memória intermédia de saída ou, alternadamente remove um a substituí-lo. Oe Qconstruir as paredes esquerda e superior, respectivamente, e F f males o restante do retângulo por busca iterativa.

Embora a pesquisa básica seja iterativa, eliminamos a grande maioria dos vetores de pesquisa possíveis, primeiro construindo as combinações permitidas de largura e altura para o retângulo mestre e, em seguida, eliminando configurações impossíveis. Pode-se obter velocidade adicional em retângulos maiores, determinando as paredes inferior e direita antes de encher o centro, mas não é necessária uma velocidade decente ao limitar a 25 retângulos internos.


Bom trabalho! Parece estar funcionando ... No entanto, você poderia especificar seu formato de saída? Parece que está imprimindo coisas se funcionar e travando se não funcionar, o que vou permitir, já que essa é a única resposta. Além disso, você pode salvar alguns bytes imprimindo "1" em vez de "Todo mundo se encaixa!" (porque isso é permitido) e também alguns bytes por não imprimir como estão organizados. É bom ter isso impresso, mas ele usa bytes desnecessários, e o objetivo é economizar nisso. Caso contrário, bom trabalho! Estou prorrogando o prazo por meio mês, mas por enquanto, tenho um voto positivo. :)
HyperNeutrino 3/17/17

Obrigado. Atualizei para especificar o formato e corrigi a falha (não intencional). Deixei a saída de matriz (+ 30bytes) porque é bacana e se alguém mensagens uma solução de linguagem de golfe, eles não vão ser apenas me bater por 30 :)
Seth

-367 bytes ... Possivelmente o maior golfe de todos os tempos? :-)
HyperNeutrino 3/17/17

:-) Bem, isso ajuda a ter um ponto de partida para hackers.
Seth

Com certeza! Meu maior golfe foi de 337 caracteres em Java em várias edições, e eu comecei com algumas idéias bastante terríveis (ah, os bons velhos tempos em que eu criava 50 milhões de variáveis ​​e precisava apenas de 2 ...). De qualquer forma, continuarei esperando respostas, mas parece que esse pode ser o único que funciona!
HyperNeutrino 4/17/17

6

Haskell, 226 bytes

((y,z):l)&(w,x)|x*y<1=(w+y,x+z):l
(q:l)&p=p:q:l
(p@(u,v):r@(y,z):l)%q@(w,x)=[((y-w,z):l)&q&(u,v-x)|w<=y,x<=v]++[p:m|m<-(r:l)%q]
_%_=[]
g m(p:n)l=any(g[]$m++n)(l%p)||g(p:m)n l
g[]_[_,_,_]=0<1
g _[]_=0<0
($[(0,9^9),(9^9,0)]).g[]

Experimente no Ideone

Como funciona

Isso recursivamente pesquisa todas as inclinações parciais cuja forma é um diagrama de Young , adicionando um retângulo por vez e verifica se algum dos resultados finais são retângulos.

Para ver que qualquer lado a lado de um retângulo pode ser construído dessa maneira: em qualquer lado a lado de um diagrama de Young não vazio, seja R o conjunto de retângulos no lado a lado cujo canto sudoeste não toque em nenhum outro retângulo. Como cada vértice côncavo do diagrama de Young é adjacente à aresta (não apenas adjacente ao canto) a no máximo um retângulo em R, e o número desses vértices côncavos é um menor que o número de retângulos em R, deve haver pelo menos um retângulo em R que é adjacente à borda de nenhum desses vértices côncavos. Removê-lo produz outro diagrama de Young, para que possamos prosseguir por indução.


Agradável! Isto é fantástico. Bom trabalho! :)
HyperNeutrino
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.