Ordenar pila de libros

21

Al apilar libros, generalmente desea colocar los más grandes en la parte inferior y los más pequeños en la parte superior. Sin embargo, mi TOC latente me hace sentir muy incómodo si tengo dos libros donde uno es más corto (en altura) pero más ancho que el otro. No importa en qué orden los coloque, el libro superior se extenderá más allá del libro inferior en un lado.

Como ejemplo, digamos que un libro tiene dimensiones (10,15)y otro tiene dimensiones (11,14). No importa en qué dirección los coloque, me sale un saliente. Pero si tengo libros con dimensiones (4,3)y (5,6), puedo evitar sobresalir colocando el último debajo del primero.

A los fines de este desafío, consideraremos los voladizos solo en relación con el libro que se encuentra a continuación . Por ejemplo, si tengo una pila (5,5), (3,3), (4,4)(no es que cualquier persona sana haría eso), los recuentos de libros como un voladizo superior, a pesar de que no se extiende más allá del libro de fondo. Del mismo modo, la pila (3,3), (3,3), (4,4)también tiene sólo un voladizo, a pesar del libro superior que se extiende más allá de la parte inferior.

El reto

Dada una lista de pares enteros para las dimensiones de los libros, clasifique esos pares / libros de modo que el número de voladizos sea mínimo. No debe rotar los libros: quiero que todas las espinas estén orientadas en la misma dirección. Si hay varias soluciones con el mismo número de voladizos, puede elegir cualquier orden. Su algoritmo de clasificación no tiene que ser estable. Su implementación puede suponer que las dimensiones del libro son inferiores a 2 16 cada una.

Complejidad del tiempo: para hacer esto un poco más interesante, la complejidad asintótica del peor de los casos de su algoritmo debe ser polinomial en el tamaño de la pila. Por lo tanto, no puede probar cada permutación posible. Incluya una breve prueba de la optimización y complejidad de su algoritmo y, opcionalmente, un gráfico que muestre la escala para entradas aleatorias grandes. Por supuesto, no puede usar el tamaño máximo de la entrada como argumento de que su código se ejecuta en O (1).

Puede escribir un programa o función, recibir información a través de STDIN, ARGV o argumento de función en cualquier formato de lista conveniente (no preprocesado) e imprimir o devolver el resultado.

Este es el código de golf, por lo que gana la respuesta más corta (en bytes).

Estoy seguro de que existe una solución polinómica, pero si puede demostrar que estoy equivocado, puede presentar dicha prueba en lugar de una presentación de golf. En este caso, puede suponer P ≠ NP . Aceptaré la primera prueba correcta y le otorgaré una recompensa.

Ejemplos

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

Los creé a mano, así que avísame si ves algún error.

Martin Ender
fuente
3
¿Está seguro de que encontrar una solución con un número mínimo de voladizos se puede resolver en tiempo polinómico?
COTO
@COTO Estoy bastante seguro, sí.
Martin Ender
Hmm Normalmente lo abordaría con un algoritmo codicioso, pero puedo obtener fácilmente entradas que conduzcan a salidas subóptimas para cualquier criterio de "codicia" que se me ocurra (por ejemplo, área, maximizar una dimensión, maximizar la dimensión más pequeña, etc.). Los únicos otros enfoques que se me ocurren implican dividir los libros en camarillas, y todos ellos tienen una exponencial complejidad en el peor de los casos. Me interesará ver qué respuestas surgen. También es posible que desee solicitar una breve prueba de la optimización del tipo como parte de la especificación.
COTO
@COTO He agregado un párrafo sobre esto en caso de que realmente esté equivocado, pero no cuente con eso. ;)
Martin Ender
Por si acaso, las pruebas potenciales de que no existe un algoritmo de tiempo polinómico deben permitirse suponer que P no es igual a NP.
xnor

Respuestas:

2

Pyth , 30

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

Este es un campo directo del asombroso algoritmo de GRC. Aquí está el equivalente preciso del programa pyth anterior, en su código compilado de python.

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))

En este contexto, la Psum(Y)función es equivalente a la pitón sum(Y,[]).

Código compilado y ejecutado real (desde 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))
isaacg
fuente
1
La traducción de Python necesita "Y = []", elimine la evaluación si está en Python 2, y la suma necesita un segundo argumento sum(Y,[]). Todo esto debería funcionar en Pyth, solo la traducción no lo incluye automáticamente.
xnor
@xnor La última línea realmente lee: Pprint("\n",Psum(Y)). Creo que puede haberlo simplificado por conveniencia, junto con todos los -1s, etc., en Psumrealidad funcionarían más 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,[])

Después de ordenar la lista de libros en orden descendente (primero por ancho y luego por altura), esto divide los libros en pilas sin superposiciones. Para determinar dónde colocar cada libro, su altura se compara con la altura del libro superior en cada pila. Se coloca en la primera pila posible, o se crea una nueva pila.

No soy muy bueno con la complejidad del tiempo, pero creo que sería el peor de los casos de O ( N 2 ). Hay dos bucles, cada uno con N iteraciones como máximo . También uso el tipo integrado de Python, que es O ( n log n ).


Mi primera prueba de que este algoritmo produce soluciones óptimas resultó ser incorrecta. Un gran agradecimiento a @xnor y @ Sp3000 por una gran discusión en el chat sobre probar esto (que puedes leer comenzando aquí ). Después de elaborar una prueba correcta, @xnor descubrió que parte de ella ya se había hecho ( teorema de Dilworth ).

Aquí hay una descripción general de la prueba de todos modos (crédito a @xnor y @ Sp3000).

Primero, definimos la noción de un antipile o antichain ( citado de @xnor ):

Un antipile es una secuencia de libros de altura decreciente, pero el aumento de la anchura
Así, cada libro sucesivo es estrictamente más alto pero estrictamente menos ancho
Observe que cualquier libro en un voladizos antipile más de cualquier otro libro en una antipile
tanto, no hay dos libros dentro de una lata antipile estar en la misma pila
Como consecuencia, si puede encontrar un antipile de x libros, entonces esos libros deben estar en diferentes montones.
Entonces, el tamaño del antipile más grande es un límite inferior en el número de montones

Luego, clasificamos los libros en orden descendente por su ancho (primero) y su altura (segundo) *.

Para cada libro B , hacemos lo siguiente:

  1. Si B puede caber en la primera pila, lo colocamos allí y seguimos adelante.
  2. De lo contrario, encontramos el primer * stack x sobre el que B se puede colocar encima. Esto puede ser una nueva pila si es necesario.
  3. A continuación, vinculamos B a P , donde P es el primer libro en la pila anterior x - 1 .
  4. Ahora sabemos que:
    • B es estrictamente * más pequeño en ancho que P , ya que los libros están ordenados en orden descendente por ancho
    • B es estrictamente mayor en altura que P , o habríamos colocado a B encima de P

Ahora, hemos construido un enlace de cada libro (excepto los de la primera pila), a un libro en la pila anterior que es mayor en ancho y menor en altura.

El excelente diagrama de @ Sp3000 ilustra esto bien:

Al seguir cualquier camino desde el último montón (a la derecha), hasta el primer montón (a la izquierda), obtenemos un antipile. Es importante destacar que la longitud de este antipile es igual al número de pilas. Por lo tanto, el número de pilas utilizadas es mínimo.

Finalmente, dado que hemos organizado los libros en la cantidad mínima de pilas sin superposiciones, podemos apilarlas una encima de la otra para obtener una pila con la cantidad mínima de superposiciones.

* este útil comentario explica algunas cosas

grc
fuente
3
+1 para la prueba expositiva y el enlace a la discusión. Apoyos para xnor et al.
COTO
Debo aclarar que el Teorema de Dilworth no cubre toda la prueba, solo el hecho de que el menor número de pilas es igual al antipile de mayor tamaño.
xnor