Ordinamento pila di libri


21

Quando impili i libri di solito vuoi mettere quelli più grandi in basso e quelli più piccoli in alto. Tuttavia, il mio DOC latente mi fa sentire molto a disagio se ho due libri in cui uno è più corto (in altezza) ma più largo dell'altro. Indipendentemente dall'ordine in cui li inserisco, il libro superiore si estenderà oltre il libro inferiore su un lato.

Ad esempio, supponiamo che un libro abbia dimensioni (10,15)e un altro abbia dimensioni (11,14). Non importa in che modo li metto, ottengo una sporgenza. Ma se ho libri con dimensioni (4,3)e (5,6), posso evitare uno strapiombo posizionando quest'ultimo sotto il primo.

Ai fini di questa sfida considereremo gli strapiombi solo in relazione al libro immediatamente sotto . Ad esempio, se ho una pila (5,5), (3,3), (4,4)(non che nessuna persona sana di mente avrebbe fatto), i conteggi top libro come una sporgenza, anche se non si estende oltre il libro di fondo. Analogamente, la pila (3,3), (3,3), (4,4)ha anche una sola sporgenza, nonostante il libro superiore si estende oltre quello inferiore.

La sfida

Dato un elenco di coppie intere per le dimensioni del libro, ordina quelle coppie / libri in modo tale che il numero di sporgenze sia minimo. Non devi ruotare i libri: voglio che tutte le spine siano rivolte nella stessa direzione. Se esistono più soluzioni con lo stesso numero di sporgenze, è possibile scegliere un tale ordine. L'algoritmo di ordinamento non deve essere stabile. L'implementazione potrebbe presumere che le dimensioni del libro siano inferiori a 2 16 ciascuna.

Complessità temporale: per renderlo un po 'più interessante, la complessità asintotica nel caso peggiore dell'algoritmo deve essere polinomiale nelle dimensioni dello stack. Quindi non puoi semplicemente testare ogni possibile permutazione. Includi una breve prova dell'ottimalità e della complessità dell'algoritmo e, facoltativamente, un grafico che mostra il ridimensionamento per input casuali di grandi dimensioni. Naturalmente, non è possibile utilizzare la dimensione massima dell'input come argomento per l'esecuzione del codice in O (1).

È possibile scrivere un programma o una funzione, accettare input tramite STDIN, ARGV o argomento della funzione in qualsiasi formato di elenco conveniente (non preelaborato) e stampare o restituire il risultato.

Questo è il golf del codice, quindi vince la risposta più breve (in byte).

Sono fiducioso che esista una soluzione polinomiale, ma se puoi dimostrarmi che mi sbaglio, puoi presentare una prova del genere invece di una richiesta golfata. In questo caso, puoi assumere P ≠ NP . Accetterò la prima prova corretta e assegnerò un premio ad essa.

Esempi

In:  [[1, 1], [10, 10], [4, 5], [7, 5], [7, 7], [10, 10], [9, 8], [7, 5], [7, 5], [3, 1]]
Out: [[10, 10], [10, 10], [9, 8], [7, 7], [7, 5], [7, 5], [7, 5], [4, 5], [3, 1], [1, 1]]

In:  [[4, 5], [5, 4], [5, 4], [5, 4], [5, 4], [4, 5], [4, 5], [4, 5], [5, 4], [4, 5]]
Out: [[4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [5, 4], [5, 4], [5, 4], [5, 4], [5, 4]]
  or [[5, 4], [5, 4], [5, 4], [5, 4], [5, 4], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5]]

In:  [[2, 3], [1, 1], [5, 5], [7, 1]]
Out: [[5, 5], [2, 3], [7, 1], [1, 1]]
 or  [[5, 5], [2, 3], [1, 1], [7, 1]]
 or  [[7, 1], [5, 5], [2, 3], [1, 1]]
 or  [[7, 1], [1, 1], [5, 5], [2, 3]]

Li ho creati a mano, quindi fatemi sapere se individuate degli errori.


3
Sei sicuro che trovare una soluzione con un numero minimo di sporgenze possa essere risolto in un tempo polinomiale?
COTO

@COTO Sono abbastanza fiducioso, sì.
Martin Ender,

Hmm. Normalmente lo affronterei con un algoritmo avido, ma posso facilmente procurarmi input che portano a risultati non ottimali per qualsiasi criterio di "avidità" che posso elaborare (ad es. Area, massimizzare una dimensione, massimizzare la dimensione più piccola, ecc.). Gli unici altri approcci che riesco a pensare riguardano il partizionamento dei libri in cricche e tutti hanno una complessità esponenziale nel caso peggiore. Sarò interessato a vedere quali risposte arrivano. Potresti anche richiedere una breve prova dell'ottimalità dell'ordinamento come parte delle specifiche.
COTO

@COTO Ho aggiunto un paragrafo su questo nel caso in cui mi sbagli, ma non ci contare. ;)
Martin Ender,

Per ogni evenienza, le prove potenziali che non esiste un algoritmo del tempo polinomiale dovrebbero poter supporre che P non sia uguale a NP.
xnor

Risposte:


2

Pyth , 30

FN_SQFbYIgeeYeb~b]NB)E~Y]]N;sY

Questo è un golf diretto dell'algoritmo fantastico di grc. Ecco l'equivalente preciso del programma pyth sopra, nel suo codice python compilato.

Q = eval(input())
Y = []
for N in sorted(Q)[::-1]:
     for b in Y:
         if Y[-1][-1] >= b[-1]:
             b += [N]
             break
     else:
         Y += [[N]]
print(Psum(Y))

In questo contesto, la Psum(Y)funzione è equivalente a Python sum(Y,[]).

Codice effettivo compilato ed eseguito (da pyth -d):

Y=[]
Q=copy(eval(input()))
for N in neg(Psorted(Q)):
 for b in Y:
  if gte(end(end(Y)),end(b)):
   b+=[N]
   break
 else:
  Y+=[[N]]
Pprint("\n",Psum(Y))

1
La traduzione di Python richiede "Y = []", rimuovi l'eval se sei in Python 2 e la somma ha bisogno di un secondo argomento sum(Y,[]). Tutto questo dovrebbe funzionare in Pyth, solo la traduzione non lo include automaticamente.
xnor

@xnor L'ultima riga si legge davvero: Pprint("\n",Psum(Y)). Penso che potrebbe averlo semplificato per comodità, insieme a tutti gli altri -1, in Psumrealtà funzionerebbe più come reduce(lambda x,y:x+y, Y[1:], Y[0]).
FryAmTheEggman,

20

Python, 113

P=[]
for n in sorted(input())[::-1]:
 for p in P:
  if p[-1][1]>=n[1]:p+=[n];break
 else:P+=[[n]]
print sum(P,[])

Dopo aver ordinato l'elenco dei libri in ordine decrescente (prima per larghezza e poi per altezza), questo suddivide i libri in pile senza sovrapposizioni. Per determinare dove posizionare ciascun libro, la sua altezza viene confrontata con l'altezza del libro in cima a ogni pila. Viene posizionato sulla prima pila possibile, oppure viene creata una nuova pila.

Non sono molto bravo con la complessità temporale, ma credo che avrebbe il caso peggiore di O ( N 2 ). Esistono due loop, ciascuno con al massimo N iterazioni. Uso anche l'ordinamento incorporato di Python, che è O ( n log n ).


La mia prima prova che questo algoritmo produce soluzioni ottimali si è rivelata errata. Un enorme ringraziamento va a @xnor e @ Sp3000 per una grande discussione nella chat sulla dimostrazione di ciò (che potete leggere a partire da qui ). Dopo aver elaborato una prova corretta, @xnor ha scoperto che parte di essa era già stata eseguita ( teorema di Dilworth ).

Ecco comunque una panoramica della prova (credito a @xnor e @ Sp3000).

Innanzitutto, definiamo la nozione di un antipile, o antichain, ( citato da @xnor ):

Un antipile è una sequenza di libri di altezza decrescente, ma crescente di larghezza.
Quindi, ogni libro successivo è rigorosamente più alto ma rigorosamente meno ampio.
Si noti che qualsiasi libro in un antipile sovrasta qualsiasi altro libro in un antipile
Quindi, non ci sono due libri all'interno di un antipile essere nella stessa pila
Di conseguenza, se riesci a trovare un antipile di x libri, allora quei libri devono essere in pile diverse
Quindi, la dimensione del più grande antipile è un limite inferiore sul numero di pile

Quindi, ordiniamo i libri in ordine decrescente per larghezza (primo) e altezza (secondo) *.

Per ogni libro B , facciamo come segue:

  1. Se B si adatta alla prima pila, la posizioniamo lì e andiamo avanti.
  2. Altrimenti, troviamo il primo * mucchio x di cui B può essere posizionato sopra. Questa può essere una nuova pila, se necessario.
  3. Quindi, colleghiamo B a P , dove P è il libro in cima alla pila precedente x - 1 .
  4. Ora sappiamo che:
    • B è strettamente * più piccola in larghezza di P , poiché i libri sono ordinati in ordine decrescente per larghezza
    • B è strettamente maggiore in altezza di P , altrimenti avremmo posto B sopra P

Ora, abbiamo creato un collegamento da ogni libro (tranne quelli nella prima pila), a un libro nella pila precedente che è maggiore in larghezza e in altezza.

L'ottimo diagramma di @ Sp3000 lo illustra bene:

Seguendo qualsiasi percorso dall'ultima pila (a destra), alla prima pila (a sinistra), otteniamo un antipile. È importante sottolineare che la lunghezza di questo antipile è uguale al numero di pile. Quindi, il numero di pile utilizzate è minimo.

Infine, poiché abbiamo organizzato i libri nel numero minimo di pile senza sovrapposizioni, possiamo impilarli uno sopra l'altro per ottenere una pila con il numero minimo di sovrapposizioni.

* questo utile commento spiega alcune cose


3
+1 per la prova espositiva e collegamento alla discussione. Prop a xnor et al.
COTO

Dovrei chiarire che il Teorema di Dilworth non copre l'intera dimostrazione, solo il fatto che il minor numero di pile è uguale all'antipile di dimensioni maggiori.
xnor
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.