L'idée de ce défi de code est simple: étant donné une matrice d'entiers, trions-la en appliquant des mouvements de style Rubik. Cela signifie que vous pouvez sélectionner une seule ligne ou colonne et faire pivoter ses éléments dans n'importe quelle direction:
[1, 3, 2, 4] => [3, 2, 4, 1] (rotate left for rows/up for columns)
[1, 3, 2, 4] => [4, 1, 3, 2] (rotate right for rows/down for columns)
Donc, étant donné une matrice d'entiers de n'importe quelle dimension, triez ses éléments en appliquant uniquement ces transformations de style Rubik. Une matrice
sera considéré trié si ses éléments respectent la restriction suivante:
E / S
- L'entrée sera une matrice d'entiers positifs sans valeurs répétées.
- La sortie sera les mouvements nécessaires pour le trier. Comme ce n'est pas un défi de golf de code et que vous n'avez pas à vous soucier de sa longueur, le format proposé pour chaque mouvement est
#[UDLR]
où#
est le numéro de la ligne ou de la colonne à déplacer (indexé 0) et[UDLR]
est un seul caractère dans ce plage qui spécifie si le mouvement est Haut / Bas (pour les colonnes) ou Gauche / Droite (pour les lignes). Cela1U
signifierait donc "déplacer la 1ère colonne vers le haut" mais1R
serait "déplacer la 1ère ligne vers la droite". Les mouvements seront séparés par des virgules, donc une solution sera exprimée comme suit:1R,1U,0L,2D
.
Notation
Essayer de trier une matrice de cette façon peut être coûteux car il y a beaucoup de combinaisons possibles de mouvements, et il y a aussi beaucoup de listes possibles de mouvements qui peuvent le trier, donc l'objectif est d'écrire du code qui trie le N * N matrices ci-dessous. Le score sera la plus grande taille N que vous pourrez résoudre en un temps raisonnable 1 sans erreurs (plus la taille de la matrice résolue est grande, mieux c'est). En cas d'égalité, le bris d'égalité sera le nombre de mouvements dans votre chemin trouvé (plus le chemin est court, mieux c'est).
Exemple: si un utilisateur A trouve une solution pour N = 5 et B trouve une solution pour N = 6, B gagne quelle que soit la longueur des deux chemins. S'ils trouvent tous les deux des solutions pour N = 6 mais que la solution trouvée par A a 50 étapes et la solution de B a 60 étapes, A gagne.
Les explications sur le fonctionnement de votre code sont fortement encouragées et veuillez publier les solutions trouvées afin que nous puissions les tester . Vous pouvez utiliser Pastebin ou des outils similaires si les solutions sont trop importantes. De plus, une estimation du temps passé par votre code à trouver vos solutions sera appréciée.
Cas de test
Les matrices suivantes ( lien Pastebin pour une version plus copiable) ont été créées à partir de matrices déjà triées en les brouillant avec des mouvements aléatoires de style Rubik de 10K:
Cas de test en texte clair:
[[8, 5, 6], [11, 10, 1], [3, 15, 13]]
[[21, 10, 12, 16], [17, 6, 22, 14], [8, 5, 19, 26], [13, 24, 3, 1]]
[[1, 13, 8, 16, 5], [9, 40, 21, 26, 22], [11, 24, 14, 39, 28], [32, 19, 37, 3, 10], [30, 17, 36, 7, 34]]
[[34, 21, 40, 22, 35, 41], [18, 33, 31, 30, 12, 43], [19, 11, 39, 24, 28, 23], [44, 1, 36, 5, 38, 45], [14, 17, 9, 16, 13, 26], [8, 3, 47, 6, 25, 4]]
[[20, 36, 17, 1, 15, 50, 18], [72, 67, 34, 10, 32, 3, 55], [42, 43, 9, 6, 30, 61, 39], [28, 41, 54, 27, 23, 5, 70], [48, 13, 25, 12, 46, 58, 63], [52, 37, 8, 45, 33, 14, 68], [59, 65, 56, 73, 60, 64, 22]]
[[85, 56, 52, 75, 89, 44, 41, 68], [27, 15, 87, 91, 32, 37, 39, 73], [6, 7, 64, 19, 99, 78, 46, 16], [42, 21, 63, 100, 4, 1, 72, 13], [11, 97, 30, 93, 28, 40, 3, 36], [50, 70, 25, 80, 58, 9, 60, 84], [54, 96, 17, 29, 43, 34, 23, 35], [77, 61, 82, 48, 2, 94, 38, 66]]
[[56, 79, 90, 61, 71, 122, 110, 31, 55], [11, 44, 28, 4, 85, 1, 30, 6, 18], [84, 43, 38, 66, 113, 24, 96, 20, 102], [75, 68, 5, 88, 80, 98, 35, 100, 77], [13, 21, 64, 108, 10, 60, 114, 40, 23], [47, 2, 73, 106, 82, 32, 120, 26, 36], [53, 93, 69, 104, 54, 19, 111, 117, 62], [17, 27, 8, 87, 33, 49, 15, 58, 116], [95, 112, 57, 118, 91, 51, 42, 65, 45]]
Veuillez demander plus si vous les résolvez tous. :-) Et merci beaucoup aux personnes qui m'ont aidé à affiner ce défi dans le bac à sable .
1 Un temps raisonnable: tout temps qui ne sape pas notre patience lors du test de votre solution. Notez que TIO n'exécute le code que pendant 60 secondes, tout laps de temps dépassant cette limite nous fera tester le code dans nos machines. Exemple: mon algorithme plutôt inefficace prend quelques millisecondes pour résoudre des matrices d'ordre 3x3 et 4x4, mais je viens de le tester avec une matrice 5x5 et il a fallu 317 secondes pour le résoudre (en plus de 5 millions de mouvements, très drôle si l'on considère que la matrice à résoudre a été brouillée uniquement 10 000 fois). J'ai essayé de réduire le nombre de mouvements à moins de 10K mais je me suis rendu après 30 minutes d'exécution du code.
O(input size)
alors? Pour une matrice 5x5, ce seraitO(25)
? Cela semble être extrêmement rapide, donc je serais très intéressé de voir cet algorithme ou l'implémentation du vôtre. EDIT: Vous vous rendez compte que nous entrons la matrice «brouillée» et émettons les mouvements, non? Pas l'inverse.Réponses:
Nim
Essayez-le en ligne!
Une tentative rapide pour implémenter l'algorithme de la solution de puzzle Torus à partir d'un article publié dans Algorithms 2012, 5, 18-29 que j'ai mentionné dans les commentaires.
Accepte la matrice d'entrée sous forme aplatie, comme une ligne de nombres séparés par des espaces.
Voici également un validateur en Python 2 . Il prend deux lignes en entrée: la matrice brouillée d'origine sous la même forme que le code principal et la séquence de mouvements proposée. La sortie du validateur est la matrice résultant de l'application de ces mouvements.
Explication
Dans la première partie de l'algorithme, nous ordonnons toutes les lignes sauf la dernière.
Pour ce faire, nous effectuons une série de "rotations triangulaires" ([ p , q] , puis trouvez la cellule [ s , t ] qui contient actuellement le numéro qui doit aller à [ p , q] et complétez le triangle rectangle en sélectionnant un troisième point [ u , v ] selon un modèle, comme le montre la figure 4 de l'article lié.
proc triangle
) - les séquences de mouvements qui se traduisent par un échange de trois cellules seulement, et tout le reste restant inchangé. Nous prenons chaque cellule "de travail" consécutive avec des coordonnéesDans la Fig.2, les auteurs présentent 8 modèles possibles et les séquences de mouvements correspondantes, mais dans mon code, tous les cas ont été couverts par seulement 5 modèles, de sorte que non. 1, 5 et 6 ne sont pas utilisés.
Dans la deuxième partie, la dernière ligne, à l'exception des deux derniers éléments, est ordonnée en effectuant "trois rotations d'éléments" sur une ligne (
proc line
), qui consistent en deux rotations triangulaires chacune (voir la figure 3 de l'article).Nous sélectionnons notre cellule de travail actuelle[ p , q] comme point gauche, cellule contenant la valeur cible [ s , t ] comme point central, et [ s , t + 1 ] comme le bon point. Ce mouvement en direction ouest est nomméTW dans l'article, tout comme mon processus de formation de chaîne pour cela. Sit est déjà la dernière colonne, de sorte que t + 1 n'existe pas, on prend [ s , t - 1 ] comme troisième point, et modifiez l'action en conséquence: deux rotations de triangle sont effectuées par les motifs 7 et 8 (au lieu de 7 et 1 dans l'original TW séquence).
Enfin, sin est étrange, les deux éléments restants doivent être déjà en place, car nous sommes garantis qu'une solution existe. Sin est pair, et les deux éléments restants ne sont pas en place, alors selon le lemme 1 (page 22), ils peuvent être échangés par une série de TW se déplace, suivi d'un décalage vers l'est (= R ). Étant donné que l'exemple fourni échange les deux premières entrées et que nous devons échanger les deux dernières, notre TW se déplace dans l'ordre inverse.
proc swap
effectueDans le cas de bord den = 2 nous n'avons pas du tout besoin de toutes ces procédures complexes - si les derniers éléments de la ligne ne sont pas en place après la partie 1, un seul 1 R le mouvement est suffisant pour rendre la matrice entièrement ordonnée.
Mise à jour: Ajout d'un nouveau
proc rotations
qui inverse la direction des mouvements si cela se traduirait par moins d'étapes.la source
7L,7L,7L,7L,7D,7D,7D,7D
ceux qui peuvent être réduits et8R,8R,8R,8R,8R,8R,8R
ceux qui peuvent être convertis8L,8L
pour une matrice 9x9.Python 2 , taille 100 en <30 secondes sur TIO
Essayez-le en ligne! Link comprend trois petits cas de test avec sortie de déplacement complet, plus un test silencieux de 100x100 pour montrer que le code fonctionne (la sortie de déplacement dépasserait les limites de TIO). Explication: Le code tente d'effectuer un tri par insertion sur le tableau, en le construisant dans l'ordre croissant au fur et à mesure. Pour toutes les lignes sauf la dernière ligne, il existe un certain nombre de cas:
Les rotations ci-dessus sont effectuées dans la direction qui minimise le nombre de pas; un carré de taille 2 est toujours résolu à l'aide de mouvements vers la gauche et vers le haut, quelle que soit la description ci-dessus.
Avant que la rangée du bas ne soit terminée, elle est tournée pour minimiser la distance totale hors de sa place, mais aussi pour s'assurer que la parité de la rangée du bas est régulière, car elle ne peut pas être modifiée par la dernière partie de l'algorithme. S'il y a plus d'une rotation avec la même distance minimale, la rotation avec le plus petit nombre de mouvements est choisie.
L'algorithme de la ligne du bas repose sur une séquence de 7 opérations qui échange les éléments en trois colonnes. La séquence est appliquée à chacun des numéros restants de la rangée inférieure afin de les amener à leur tour à l'emplacement souhaité; si possible, l'élément de cet emplacement est déplacé vers son emplacement souhaité, mais si un échange direct est nécessaire, l'élément est simplement déplacé vers la colonne disponible la plus proche, ce qui, espérons-le, peut être corrigé la prochaine fois.
la source