Tri de la pile de livres

21

Lorsque vous empilez des livres, vous devez généralement placer les plus grands en bas et les plus petits en haut. Cependant, mon TOC latent me met très mal à l'aise si j'ai deux livres où l'un est plus court (en hauteur) mais plus large que l'autre. Peu importe l'ordre dans lequel je les place, le livre supérieur s'étendra au-delà du livre inférieur d'un côté.

Par exemple, disons qu'un livre a des dimensions (10,15)et un autre a des dimensions (11,14). Peu importe où je les mets, j'obtiens un surplomb. Mais si j'ai des livres avec des dimensions (4,3)et (5,6), je peux éviter un surplomb en plaçant ces derniers en dessous des premiers.

Aux fins de ce défi, nous ne considérerons les surplombs que par rapport au livre immédiatement ci-dessous . Par exemple , si j'ai une pile (5,5), (3,3), (4,4)(pas que toute personne saine d' esprit ferait cela), les chefs de livre en haut comme un surplomb, même si elle ne dépasse pas le livre de fond. De même, la pile (3,3), (3,3), (4,4)a aussi un seul faux, malgré le livre de haut qui dépasse celui du bas.

Le défi

Étant donné une liste de paires entières pour les dimensions du livre, triez ces paires / livres de sorte que le nombre de porte-à-faux soit minimal. Vous ne devez pas faire tourner les livres - je veux que toutes les épines soient orientées dans la même direction. S'il existe plusieurs solutions avec le même nombre de porte-à-faux, vous pouvez choisir une telle commande. Votre algorithme de tri n'a pas besoin d'être stable. Votre implémentation peut supposer que les dimensions du livre sont inférieures à 2 16 chacune.

Complexité temporelle: pour rendre cela un peu plus intéressant, la complexité asymptotique du pire des cas de votre algorithme doit être polynomiale dans la taille de la pile. Vous ne pouvez donc pas simplement tester toutes les permutations possibles. Veuillez inclure une courte preuve de l'optimalité et de la complexité de votre algorithme et éventuellement un tracé qui montre la mise à l'échelle pour les grandes entrées aléatoires. Bien sûr, vous ne pouvez pas utiliser la taille maximale de l'entrée comme argument que votre code s'exécute dans O (1).

Vous pouvez écrire un programme ou une fonction, saisir des données via STDIN, ARGV ou un argument de fonction dans n'importe quel format de liste pratique (non prétraité) et imprimer ou renvoyer le résultat.

Il s'agit du code golf, donc la réponse la plus courte (en octets) l'emporte.

Je suis convaincu qu'il existe une solution polynomiale, mais si vous pouvez me prouver le contraire, vous pouvez soumettre une telle preuve au lieu d'une soumission golfée. Dans ce cas, vous pouvez supposer P ≠ NP . J'accepterai la première bonne preuve et je lui accorderai une prime.

Exemples

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

Je les ai créés à la main, alors faites-moi savoir si vous repérez des erreurs.

Martin Ender
la source
3
Êtes-vous certain que trouver une solution avec un nombre minimum de porte-à-faux peut être résolu en temps polynomial?
COTO
@COTO Je suis assez confiant, oui.
Martin Ender
Hmm. Je l'aborderais normalement avec un algorithme gourmand, mais je peux facilement me procurer des entrées menant à des sorties sous-optimales pour tout critère de «cupidité» que je peux trouver (par exemple, zone, maximiser une dimension, maximiser la plus petite dimension, etc.). Les seules autres approches auxquelles je peux penser consistent à partitionner les livres en cliques, et toutes ont une complexité exponentielle dans le pire des cas. Je serai intéressé de voir quelles réponses arriveront. Vous pouvez également demander une brève preuve de l'optimalité du tri dans le cadre de la spécification.
COTO
@COTO J'ai ajouté un paragraphe à ce sujet au cas où je me trompe, mais ne comptez pas dessus. ;)
Martin Ender
Juste au cas où, les preuves potentielles de l'absence d'algorithme en temps polynomial devraient être autorisées à supposer que P n'est pas égal à NP.
2014 à 6h09

Réponses:

2

Pyth , 30

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

Ceci est un golf direct de l'algorithme génial de grc. Voici l'équivalent précis du programme pyth ci-dessus, dans son code python compilé.

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

Dans ce contexte, la Psum(Y)fonction est équivalente au python sum(Y,[]).

Code réel compilé et exécuté (à partir de 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
la source
1
La traduction Python a besoin de "Y = []", supprimez l'eval si vous êtes en Python 2, et la somme a besoin d'un second argument sum(Y,[]). Tout cela devrait fonctionner en Pyth, juste la traduction ne l'inclut pas automatiquement.
2014
@xnor La dernière ligne se lit vraiment: Pprint("\n",Psum(Y)). Je pense qu'il a peut - être simplifié pour la commodité, ainsi que tous les -1s , etc. Psumserait en fait fonctionner plus comme 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,[])

Après avoir trié la liste des livres par ordre décroissant (d'abord en largeur puis en hauteur), cela partitionne les livres en piles sans chevauchements. Pour déterminer où placer chaque livre, sa hauteur est comparée à la hauteur du livre supérieur dans chaque pile. Il est placé sur la première pile possible, sinon une nouvelle pile est créée.

Je ne suis pas très bon avec la complexité du temps, mais je pense qu'il aurait un pire cas de O ( N 2 ). Il y a deux boucles, chacune avec au plus N itérations. J'utilise également le tri intégré de Python, qui est O ( n log n ).


Ma première preuve que cet algorithme produit des solutions optimales s'est avérée incorrecte. Un grand merci va à @xnor et @ Sp3000 pour une grande discussion dans le chat sur la preuve de cela (que vous pouvez lire en commençant ici ). Après avoir élaboré une preuve correcte, @xnor a constaté qu'une partie de celle-ci avait déjà été effectuée ( théorème de Dilworth ).

Voici tout de même un aperçu de la preuve (crédit à @xnor et @ Sp3000).

Tout d'abord, nous définissons la notion d'antipile, ou antichain, ( citée de @xnor ):

Un antipile est une suite de livres de hauteur décroissante, mais en augmentant la largeur
Ainsi, chaque successif est strictement plus grand , mais strictement moins large
Notez que tous les livres dans un surplombs antipile sur tout autre livre dans un antipile
Donc, pas de deux livres dans une boîte antipile être dans la même pile
En conséquence, si vous pouvez trouver un antipile de x livres, alors ces livres doivent être dans des piles différentes
Donc, la taille du plus grand antipile est une limite inférieure sur le nombre de piles

Ensuite, nous trions les livres par ordre décroissant selon leur largeur (première) et leur hauteur (seconde) *.

Pour chaque livre B , nous procédons comme suit:

  1. Si B peut tenir sur la première pile, nous la plaçons là et continuons.
  2. Sinon, nous trouvons la première * pile x sur laquelle B peut être placé au-dessus. Cela peut être une nouvelle pile si nécessaire.
  3. Ensuite, nous lions B à P , où P est le premier livre de la pile précédente x - 1 .
  4. Nous savons maintenant que:
    • B est strictement * plus petit en largeur que P , car les livres sont triés par ordre décroissant par largeur
    • B est strictement plus haut que P , sinon nous aurions placé B au-dessus de P

Maintenant, nous avons construit un lien à partir de chaque livre (sauf ceux de la première pile), vers un livre de la pile précédente qui est plus large et moins haut.

L'excellent diagramme de @ Sp3000 illustre bien cela:

En suivant n'importe quel chemin de la dernière pile (à droite), à ​​la première pile (à gauche), nous obtenons un antipile. Surtout, la longueur de cet antipile est égale au nombre de piles. Par conséquent, le nombre de piles utilisées est minime.

Enfin, puisque nous avons organisé les livres en un nombre minimum de piles sans chevauchements, nous pouvons les empiler les uns sur les autres pour obtenir une pile avec le nombre minimum de chevauchements.

* ce commentaire utile explique quelques choses

grc
la source
3
+1 pour la preuve expositive et lien vers la discussion. Les accessoires de xnor et al.
COTO
Je dois préciser que le théorème de Dilworth ne couvre pas toute la preuve, juste le fait que le plus petit nombre de piles équivaut à l'antipile de plus grande taille.
2014