Organizzazione di rettangoli arbitrari per riempire uno spazio


26

Questi rettangoli possono riempire uno spazio rettangolare?

Dato un mucchio di rettangoli, ti viene chiesto se possono essere disposti o meno per riempire uno spazio rettangolare.

Specifiche

Dato un mucchio di m x nrettangoli arbitrari ; 0 <= m, n <= 1000, determinare se è possibile disporle o meno in modo che coprano esattamente un'area rettangolare senza fori o sovrapposizioni. I rettangoli non possono essere ruotati e ogni rettangolo può essere posizionato una sola volta.

Ingresso

L'input per questo è molto flessibile, purché l'input fornisca una sorta di elenco di dimensioni a 2 spazi. Ad esempio, entrambi i seguenti sono validi:

Separato da spazio, ritorno

1 2
1 5
4 5
3 6

Elenco di dimensioni

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

Produzione

Qualsiasi tipo di valore vero / falso come vero / falso, 0/1, T / F, vero / falso, ecc. Se si intende utilizzare un metodo di output non molto ovvio, specificare nella risposta.

Esempi

Caso di prova 1

Ingresso:

1 1
1 5
2 6

Output: true(o qualcosa di simile)
Come organizzarlo:

XYYYYY
ZZZZZZ
ZZZZZZ

Caso di prova 2

Ingresso:

1 1
2 2

Output: false(o qualcosa di simile)
Spiegazione: Diventa ovvio che non è possibile disporre due quadrati di dimensioni diverse e allineare i bordi.

Caso di prova 3

Ingresso:

1 1
1 2
1 2
2 1
2 1

Output: true(o qualcosa di simile) Come organizzarlo:

AAB
DEB
DCC

Come sottolineato da @ETHProductions, per tutti gli altri casi di test, puoi continuare a combinare rettangoli con una lunghezza del bordo comune fino a quando non hai un solo rettangolo, quindi questo test è solo per rompere qualsiasi codice che utilizza questa idea.

Caso di prova 4

Ingresso:

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

Output: true(o qualcosa di simile)
Come organizzarlo:

AAABBBBEE
AAACCDDDD
FFFFFGGGH
FFFFFGGGH
IIIJJKKLH
IIIMMMMMH

Nota : non è necessario indicare come organizzarlo, è sufficiente determinare se non può essere organizzato.

Questo è il golf del codice, quindi vince la risposta più breve in byte! Accetterò la risposta più breve a partire dal 14 gennaio, ma mi sento libero di inviare le risposte più tardi poiché posso ancora dare voti! :)

Buon golf!

~ AL

PS Se sai quale tag dovrebbe essere applicato a questo problema, ti preghiamo di aggiungerlo, non ho assolutamente idea di cosa mettere come tag diverso da code-golf.

EDIT : il tuo programma dovrebbe essere in grado di elaborare fino a 25 rettangoli, in massimo 10 secondi su un computer decente (sarò abbastanza flessibile su questa regola).

EDIT : ho prorogato la scadenza di accettazione della presentazione fino all'ultimo giorno dell'anno, ma dubito che avrò una risposta entro ...

EDIT : ho prorogato il termine di accettazione della presentazione di 2 settimane, quindi se non arrivano più risposte entro allora, la risposta C corrente verrà accettata! :)


Prendo ogni rettangolo di input da utilizzare solo una volta?
xnor

7
Perché c'è una scadenza? Si potrebbe dire che si accetta una risposta in quel momento, ma le sfide dovrebbero essere aperte a tempo indeterminato :)
Nathan Merrill,

4
I rettangoli possono essere ruotati?
xnor

3
Bene, il tuo problema è un problema di decidibilità: "questi rettangoli orientati possono essere disposti in modo da formare un altro rettangolo con 0 rifiuti", che è un problema NP-completo (Korf, 2003: pdfs.semanticscholar.org/90a5/… ). L'algoritmo di Korf è essenzialmente una forza bruta con alcune ottimizzazioni per eliminare in modo più efficiente le configurazioni senza soluzione. Dubito che un golf di questo sarebbe inferiore a 250 caratteri nella maggior parte delle lingue.
Gabriel Benamy,

1
Il percorso facile sarebbe determinare se è possibile combinare ripetutamente due rettangoli della stessa larghezza o altezza fino a quando rimane 1 rettangolo. Questo algoritmo funziona per tutti i testcase correnti; tuttavia, non riesce [[1, 2], [2, 1], [1, 1], [1, 2], [2, 1]](che può essere organizzato ABB ACD EED). Potresti voler aggiungere questo semplice test case.
ETHproductions

Risposte:


5

C, 1135 1158 1231 1598 byte

Bene, è passata la scadenza stabilita, ma visto che non ci sono ancora risposte, eccone una (un po 'lunga) in C.

Ritorna:

  • 0 (zero) in caso di errore (non adatto)
  • Matrice completa per il successo

Aggiornare:

Il codice originale potrebbe rimanere bloccato su alcune matrici, impiegando molto più tempo dei 10 consentiti. La revisione corrente dovrebbe completare tutte le matrici in meno di 1 secondo. Ciò si ottiene 1) Ordinando i rettangoli di input e 2) saltando le dimensioni ripetute durante il montaggio.

golfed:

#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);
}

Spiegazione: Abbiamo 6 funzioni: main, O, Q, F, Le T. T t EST per vedere se c'è spazio per il rettangolo in un determinato posto. Lfil l s un rettangolo nel buffer di uscita o, alternativamente rimuove un sovrascrivendo. Oe Qcostruire le pareti sinistra e in alto, rispettivamente, e F f mali del resto del rettangolo ricerca iterativa.

Sebbene la ricerca di base sia iterativa, eliminiamo la stragrande maggioranza dei possibili vettori di ricerca, innanzitutto creando le combinazioni consentite di larghezza e altezza per il rettangolo principale e quindi eliminando configurazioni impossibili. È possibile ottenere una velocità aggiuntiva nei rettangoli più grandi determinando le pareti inferiore e destra prima di riempire il centro, ma non è necessaria per una velocità decente quando si limita a 25 rettangoli interni.


Bel lavoro! Sembra funzionare ... Tuttavia, potresti specificare il formato di output? Sembra che stia stampando cose se funziona e si blocca in caso contrario, il che permetterò poiché questa è l'unica risposta comunque. Inoltre, puoi salvare parecchi byte stampando "1" anziché "Adatto a tutti!" (perché ciò è consentito) e anche alcuni byte non stampando il modo in cui sono organizzati. È bello averlo stampato, ma utilizza byte non necessari e lo scopo è quello di risparmiare. Altrimenti, buon lavoro! Prolungo la scadenza di mezzo mese, ma per ora ho un voto positivo. :)
HyperNeutrino,

Grazie. Ho aggiornato per specificare il formato e risolto il crash (che non era intenzionale). Ho lasciato l'output della matrice (+ 30bytes) perché è elegante e se qualcun altro pubblica una soluzione in lingua golf, non mi batteranno solo per 30 :)
Seth

-367 byte ... Forse il più grande golf di sempre? :-)
HyperNeutrino,

:-) Beh, aiuta ad avere un punto di partenza hack-y.
Seth

Sicuro! Il mio golf più grande era di 337 caratteri in Java su diverse modifiche, e ho iniziato con alcune idee piuttosto terribili (oh, i bei vecchi tempi in cui avrei creato 50 milioni di variabili e ne avrei bisogno solo 2 ...). Ad ogni modo, continuerò ad aspettare risposte, ma sembra che questo possa essere l'unico funzionante!
HyperNeutrino,

6

Haskell, 226 byte

((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[]

Provalo su Ideone

Come funziona

Questo ricorsivamente cerca tutti i tetti parziali la cui forma è un diagramma di Young , aggiungendo un rettangolo alla volta e controlla se uno qualsiasi dei risultati finali sono rettangoli.

Per vedere che qualsiasi piastrellatura di un rettangolo può essere costruita in questo modo: in qualsiasi piastrellatura di un diagramma Young non vuoto, sia R l'insieme di rettangoli nella piastrellatura il cui angolo sud-ovest non tocca nessun altro rettangolo. Poiché ogni vertice concavo del diagramma di Young è adiacente al bordo (non semplicemente adiacente all'angolo) al massimo di un rettangolo in R, e il numero di questi vertici concavi è uno in meno del numero di rettangoli in R, ci deve essere almeno un rettangolo in R che è adiacente al bordo a nessuno di questi vertici concavi. Rimuovendolo si ottiene un altro diagramma Young, quindi possiamo procedere per induzione.


Ben fatto! È fantastico. Buon lavoro! :)
HyperNeutrino,
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.