[PYTHON] Défiez la tour de Hanoi avec recurs + stack

Bonsoir à tous (* ^ - ^ *)

L'autre jour, j'ai étudié la récidive dans l'article "Défier la tour de Hanoi avec récurrence". https://qiita.com/AKpirion/items/c0f7905c6227e086644e

Donc, j'ai immédiatement écrit la description suivante que @shiracamus m'a racontée. Considérez si cela peut être réalisé en ajoutant une pile.

hanoi_reference.py


def move(n, a, b, c):
    """Déplacer n disques de a vers b comme abri temporaire vers c"""
    if n > 1:
        move(n - 1, a, c, b)  #Enregistrer dans b avec c comme abri temporaire, sauf pour le bas d'un
    print(f"  {n}Aucun disque{a}De{c}Déménager à")  #Déplacer le bas de a à c
    if n > 1:
        move(n - 1, b, a, c)  #Déplacer vers c avec a comme abri temporaire, sauf pour le fond qui a été enregistré dans b

def hanoi(n):
    print(f"{n}Étapes pour déplacer un disque de A à C")
    move(n, 'A', 'B', 'C')

if __name__ == '__main__':
    hanoi(2)
    hanoi(3)

Cette fois, nous allons déplacer les deux disques comme dans l'article précédent. 図2.PNG La description récursive revient toujours à l'impression (f "déplacer le disque # {n} de {a} vers {c}"). Si tel est le cas, chaque valeur de {a} et {c} est classée par l'instruction if. Je pensais que si vous mélangez push et pop, vous pouvez réaliser la tour de Hanoi avec un stack.

Tout d'abord, j'ai préparé des piles dédiées aux positions A, B et C, respectivement.

hanoi_r1.py


class top:
      
    def __init__(self,capacity:int = 2):
        self.Astr  = [2,1]  
        self.Bstr  = [None] * capacity
        self.Cstr  = [None] * capacity
        self.capa = capacity
        self.Aptr  = 0
        self.Bptr  = 0
        self.Cptr  = 0

Je ne pense pas qu'un supplément soit nécessaire. Ensuite, il y a push, mais fondamentalement, il ne devient jamais plein, donc La description peut être simple.

hanoi_r1.py


    def Apush(self,value):
        self.Astr[self.Aptr] = value 
        self.Aptr += 1
    def Bpush(self,value):
        self.Bstr[self.Bptr] = value 
        self.Bptr += 1
    def Cpush(self,value):
        self.Cstr[self.Cptr] = value 
        self.Cptr += 1

Puisque la pop n'a pas à s'inquiéter du vide La description est simple.

hanoi_r1.py


    def Apop(self):
        self.Aptr -= 1
        return self.Astr[self.Aptr]
    def Bpop(self):
        self.Bptr -= 1
        return self.Bstr[self.Bptr]
    def Cpop(self):
        self.Cptr -= 1
        return self.Cstr[self.Cptr]

Pas de problème, non? Le reste, c'est bouger.

hanoi_r1.py


    def move(self,n,a,b,c):
        if n>1:
            top.move(self,n-1,a,c,b)
        print(f"{n}À{a}De{c}Quoi")
        if a == "A" and c == "B":
            top.Bpush(self,top.Apop(self))
            top.Apush(self,None)
            top.Apop(self)
            top.view(self)
        if a == "A" and c == "C":
            top.Cpush(self,top.Apop(self))
            top.Apush(self,None)
            top.Apop(self)
            top.view(self)
        if a == "B" and c == "C":
            top.Cpush(self,top.Bpop(self))
            top.Bpush(self,None)
            top.Bpop(self)
            top.view(self)             
        if n>1:
            top.move(self,n-1,b,a,c)

Comme je l'ai écrit au début, assurez-vous d'imprimer (f "déplacer le disque # {n} de {a} vers {c}") Puisqu'il va descendre, j'utilise if après cela pour classer les conditions. Avec trois disques, il semble qu'il y aura plus de boîtiers (rires) Je me demande s'il existe un bon moyen. .. (´Д `) y━─┛ ~~

Pour compléter un peu plus l'intérieur de l'instruction if, Puisque push / pop ne gère que le comportement du pointeur ptr, Assurez-vous de remplacer la valeur du corps de la pile A / B / C par None ou cela ne fonctionnera pas. Alors je ne pousse aucun, Le ptr sera incrémenté de 1, puis reviendra.

hanoi_r1.py


class top:
      
    def __init__(self,capacity:int = 2):
        self.Astr  = [2,1]  
        self.Bstr  = [None] * capacity
        self.Cstr  = [None] * capacity
        self.capa = capacity
        self.Aptr  = 0
        self.Bptr  = 0
        self.Cptr  = 0
        
    def Apush(self,value):
        self.Astr[self.Aptr] = value 
        self.Aptr += 1
    def Bpush(self,value):
        self.Bstr[self.Bptr] = value 
        self.Bptr += 1
    def Cpush(self,value):
        self.Cstr[self.Cptr] = value 
        self.Cptr += 1
        
    def Apop(self):
        self.Aptr -= 1
        return self.Astr[self.Aptr]
    def Bpop(self):
        self.Bptr -= 1
        return self.Bstr[self.Bptr]
    def Cpop(self):
        self.Cptr -= 1
        return self.Cstr[self.Cptr]
    
    def view(self):
        print(f"A = {self.Astr}")
        print(f"B = {self.Bstr}")
        print(f"C = {self.Cstr}")
    
    def move(self,n,a,b,c):
        if n>1:
            top.move(self,n-1,a,c,b)
        print(f"{n}À{a}De{c}Quoi")
        if a == "A" and c == "B":
            top.Bpush(self,top.Apop(self))
            top.Apush(self,None)
            top.Apop(self)
            top.view(self)
        if a == "A" and c == "C":
            top.Cpush(self,top.Apop(self))
            top.Apush(self,None)
            top.Apop(self)
            top.view(self)
        if a == "B" and c == "C":
            top.Cpush(self,top.Bpop(self))
            top.Bpush(self,None)
            top.Bpop(self)
            top.view(self)             
        if n>1:
            top.move(self,n-1,b,a,c)

test = top()

if __name__ =="__main__":
    print("default setting")
    print("A = [2,1]")
    print("B = [None,None]")
    print("C = [None,None]")
    test.move(2,"A","B","C")

Le résultat de l'exécution est ici.

default setting
A = [2,1]
B = [None,None]
C = [None,None]
1 de A à B
A = [2, None]
B = [1, None]
C = [None, None]
2 de A à C
A = [None, None]
B = [1, None]
C = [2, None]
1 de B à C
A = [None, None]
B = [None, None]
C = [2, 1]

N = 2 Non fixe, mais une configuration qui peut suivre même si elle est librement modifiée Je vais y réfléchir à nouveau. Probablement, même si le nombre de feuilles augmente, l'endroit où se déplacer n'augmente pas, donc Je sens que je peux faire quelque chose à ce sujet. Faisons-le un jour. .. ( ̄з ̄)

--10/03 18:53

La compétition sportive des enfants était terminée et il s'est couché tôt. J'ai du temps. Je vais le mettre à jour.

Le contenu de la mise à jour est de considérer une configuration capable de convertir le nombre de disques en N. Comme je l'ai mentionné brièvement la dernière fois, augmenter le nombre de disques ne signifie pas que le nombre de points mobiles augmentera. Par conséquent, il est OK si tous les modèles de mouvement sont répertoriés dans l'instruction if.

A => B A => C B => C B => A C => A C => B

Si vous pouvez diviser l'affaire, ce n'est pas intelligent Le problème peut être résolu.

hanoi_stack_r1.py


        if a == "A" and c == "B":
            top.Bpush(self,top.Apop(self))
            top.Apush(self,None)
            top.Apop(self)
            top.view(self)
        if a == "A" and c == "C":
            top.Cpush(self,top.Apop(self))
            top.Apush(self,None)
            top.Apop(self)
            top.view(self)
        if a == "B" and c == "C":
            top.Cpush(self,top.Bpop(self))
            top.Bpush(self,None)
            top.Bpop(self)
            top.view(self) 
        if a == "B" and c == "A":
            top.Apush(self,top.Bpop(self))
            top.Bpush(self,None)
            top.Bpop(self)
            top.view(self)
        if a == "C" and c == "B":
            top.Bpush(self,top.Cpop(self))
            top.Cpush(self,None)
            top.Cpop(self)
            top.view(self)
        if a == "C" and c == "A":
            top.Apush(self,top.Cpop(self))
            top.Cpush(self,None)
            top.Cpop(self)
            top.view(self)

C'est bon. Ensuite, définissez le nombre de disques à préparer N, variable.

hanoi_stack_r1.py


class top:
      
    def __init__(self,capacity):
        self.Astr  = [] * capacity     #Aucun n'est également des données, alors laissez-le vide ici
        self.Bstr  = [None] * capacity
        self.Cstr  = [None] * capacity
        self.capa = capacity
        self.Aptr  = 0
        self.Bptr  = 0
        self.Cptr  = 0
        for i in range(capacity):        #Si vous mettez 4, 0=> 1 => 2 =>3 et changer
            self.Astr.append(capacity-i) #Capacité du nombre de disques-Si je, 4=> 3 => 2 =>1 peut être attribué à Astr
        top.view(self)


if __name__ =="__main__":
    num = int(input("enter: ")) #Définissez le nombre de disques à utiliser
    test = top(num)             # def__init__Capacité de remplacement, la valeur initiale de, en nombre
    test.move(num,"A","B","C")  #num est effectivement égal à la profondeur de la pile

N'est-il pas normal de n'avoir aucun en premier lieu? !! (Lol) Je l'ai essayé avec 5 feuilles.

enter: 5
A = [5, 4, 3, 2, 1]
B = [None, None, None, None, None]
C = [None, None, None, None, None]
1 de A à C
A = [5, 4, 3, 2, None]
B = [None, None, None, None, None]
C = [1, None, None, None, None]
2 de A à B
A = [5, 4, 3, None, None]
B = [2, None, None, None, None]
C = [1, None, None, None, None]
1 de C à B
A = [5, 4, 3, None, None]
B = [2, 1, None, None, None]
C = [None, None, None, None, None]
3 de A à C
A = [5, 4, None, None, None]
B = [2, 1, None, None, None]
C = [3, None, None, None, None]
1 de B à A
A = [5, 4, 1, None, None]
B = [2, None, None, None, None]
C = [3, None, None, None, None]
2 de B à C
A = [5, 4, 1, None, None]
B = [None, None, None, None, None]
C = [3, 2, None, None, None]
1 de A à C
A = [5, 4, None, None, None]
B = [None, None, None, None, None]
C = [3, 2, 1, None, None]
4 de A à B
A = [5, None, None, None, None]
B = [4, None, None, None, None]
C = [3, 2, 1, None, None]
1 de C à B
A = [5, None, None, None, None]
B = [4, 1, None, None, None]
C = [3, 2, None, None, None]
2 de C à A
A = [5, 2, None, None, None]
B = [4, 1, None, None, None]
C = [3, None, None, None, None]
1 de B à A
A = [5, 2, 1, None, None]
B = [4, None, None, None, None]
C = [3, None, None, None, None]
3 de C à B
A = [5, 2, 1, None, None]
B = [4, 3, None, None, None]
C = [None, None, None, None, None]
1 de A à C
A = [5, 2, None, None, None]
B = [4, 3, None, None, None]
C = [1, None, None, None, None]
2 de A à B
A = [5, None, None, None, None]
B = [4, 3, 2, None, None]
C = [1, None, None, None, None]
1 de C à B
A = [5, None, None, None, None]
B = [4, 3, 2, 1, None]
C = [None, None, None, None, None]
5 de A à C
A = [None, None, None, None, None]
B = [4, 3, 2, 1, None]
C = [5, None, None, None, None]
1 de B à A
A = [1, None, None, None, None]
B = [4, 3, 2, None, None]
C = [5, None, None, None, None]
2 de B à C
A = [1, None, None, None, None]
B = [4, 3, None, None, None]
C = [5, 2, None, None, None]
1 de A à C
A = [None, None, None, None, None]
B = [4, 3, None, None, None]
C = [5, 2, 1, None, None]
3 de B à A
A = [3, None, None, None, None]
B = [4, None, None, None, None]
C = [5, 2, 1, None, None]
1 de C à B
A = [3, None, None, None, None]
B = [4, 1, None, None, None]
C = [5, 2, None, None, None]
2 de C à A
A = [3, 2, None, None, None]
B = [4, 1, None, None, None]
C = [5, None, None, None, None]
1 de B à A
A = [3, 2, 1, None, None]
B = [4, None, None, None, None]
C = [5, None, None, None, None]
4 de B à C
A = [3, 2, 1, None, None]
B = [None, None, None, None, None]
C = [5, 4, None, None, None]
1 de A à C
A = [3, 2, None, None, None]
B = [None, None, None, None, None]
C = [5, 4, 1, None, None]
2 de A à B
A = [3, None, None, None, None]
B = [2, None, None, None, None]
C = [5, 4, 1, None, None]
1 de C à B
A = [3, None, None, None, None]
B = [2, 1, None, None, None]
C = [5, 4, None, None, None]
3 de A à C
A = [None, None, None, None, None]
B = [2, 1, None, None, None]
C = [5, 4, 3, None, None]
1 de B à A
A = [1, None, None, None, None]
B = [2, None, None, None, None]
C = [5, 4, 3, None, None]
2 de B à C
A = [1, None, None, None, None]
B = [None, None, None, None, None]
C = [5, 4, 3, 2, None]
1 de A à C
A = [None, None, None, None, None]
B = [None, None, None, None, None]
C = [5, 4, 3, 2, 1]

Veuillez vérifier si quelqu'un a un problème (rires) Maintenant, voici l'indice donné par @shiracamus Je vais essayer de faire une description de type pyhton qui peut être simplifiée. J'ai lu le code de @ shiracamus, Après l'avoir lu, j'ai ri. Python peut le faire (rires). Ah ~ embarrassant (* noωno) J'écris un article pour étudier En ce moment, je m'en fiche (rires) Pour le moment, j'ai essayé de l'exécuter en premier.

test.py


tower = {"A": [*range(3, 0, -1)], "B": [], "C": []}
print(tower)
{'A': [3, 2, 1], 'B': [], 'C': []}

Qu'est-ce que c'est?! Magic ?? Au fait, si vous supprimez le * devant la plage. ..

{'A': [range(3, 0, -1)], 'B': [], 'C': []}

J'ai été surpris. Je vois, si vous ajoutez un "*" magique, Il se transforme en tableau (..) φ memo memo

Comme mentionné ci-dessus, None est également un type de données, donc Aller à vide sans utiliser Aucun, c'est la même chose.

Vient ensuite l'introduction de append () et pop (). append () se comporte comme push. De plus, la pop est comme l'idée de la pop. De plus, il est pratique de récupérer les données pour pop. Il est sur le point d'effacer les données.

.. .. .. attends une minute. Cela signifie-t-il que le contrôle géré par le pointeur n'est plus nécessaire?! Optimisons-le immédiatement, la description de def __ init __.

test.py


    def __init__(self,capacity):
        ###############################
        self.Astr  = [] * capacity     #=>  tower = {"A": [*range(n, 0, -1)], "B": [], "C": []}Remplacer par
        self.Bstr  = [None] * capacity
        self.Cstr  = [None] * capacity
        self.capa = capacity
        ###############################

        self.Aptr  = 0                #=> append,Pas besoin de variables de gestion de pointeur car l'opération de pile est réalisée par pop.
        self.Bptr  = 0
        self.Cptr  = 0

        ##############################
        for i in range(capacity):    #=>  "A": [*range(n, 0, -1)],Inutile car il est remplacé par
            self.Astr.append(capacity-i)
        top.view(self)
        ##############################
      
      # || #
      # \/ #
      
    def __init__(self,n):
         self.tower = {"A": [*range(n, 0, -1)], "B": [], "C": []}
 

J'ai ri w. Ensuite, si append et pop sont les mouvements de la pile, La description suivante qui gère l'opération du pointeur au moment du push and pop n'est pas inutile?

test.py


   #Tout inutile!!!!#####################
    def Apush(self,value):
        self.Astr[self.Aptr] = value 
        self.Aptr += 1
    def Bpush(self,value):
        self.Bstr[self.Bptr] = value 
        self.Bptr += 1
    def Cpush(self,value):
        self.Cstr[self.Cptr] = value 
        self.Cptr += 1
        
    def Apop(self):
        self.Aptr -= 1
        return self.Astr[self.Aptr]
    def Bpop(self):
        self.Bptr -= 1
        return self.Bstr[self.Bptr]
    def Cpop(self):
        self.Cptr -= 1
        return self.Cstr[self.Cptr]
    ################################

La tour est définie comme la valeur initiale, Déplaçons-le immédiatement en utilisant append et pop. En conclusion, c'est ce qui s'est passé.

test.py


class hanoi:
    
   def __init__(self,n):
         self.tower = {"A": [*range(n, 0, -1)], "B": [], "C": []}
   
   def move(self,n,a,b,c):
       if n>1:
           hanoi.move(self,n-1,a,c,b)
       print(f"{n}À{a}De{c}Quoi")
       self.tower[c].append(self.tower[a].pop())           
       if n>1:
           hanoi.move(self,n-1,b,a,c)

Ma compréhension est que self est utilisé lors du passage de variables entre des définitions en classe. Donc, si vous déclarez self.tower, vous pouvez taper def move (self,) et self. Une compréhension que vous pouvez mettre self.tower en mouvement.

Quant à hanoi.move, c'est une image qui appelle def move dans la classe hanoi. hanoi.move () J'ai été surpris. Vous devrez peut-être vous étudier un peu plus.

J'irai ensuite. Les fonctions suivantes sont définies pour représenter l'état de chaque boîte.

test.py


    def view(self):
        print(f"A = {self.Astr}")
        print(f"B = {self.Bstr}")
        print(f"C = {self.Cstr}")

Maintenant que Astr / Bstr / Cstr n'est plus nécessaire, Doit être représenté d'une autre manière. Je ne suis pas assez génial pour comprendre avec juste le code que j'ai reçu Je l'ai cherché. Il y avait une explication facile à comprendre ci-dessous.

https://note.nkmk.me/python-dict-keys-values-items/

Selon cela, le nom de la boîte et le contenu de la boîte peuvent être exprimés en tournant l'instruction for. C'était une chose.

test.py


   def view(self):
       for name,value in self.tower.items()
           print(f"{name} = {value}")

Je vois. Incorporons-le immédiatement.

test.py


class hanoi:
    
   def __init__(self,n):
         self.tower = {"A": [*range(n, 0, -1)], "B": [], "C": []}

   def view(self):
       for name,value in self.tower.items():
           print(f"{name} = {value}")
   
   def move(self,n,a,b,c):
       if n>1:
           hanoi.move(self,n-1,a,c,b)
       print(f"{n}À{a}De{c}Quoi")
       self.tower[c].append(self.tower[a].pop())
       hanoi.view(self)           
       if n>1:
           hanoi.move(self,n-1,b,a,c)

C'est assez simple de mourir. L'image entière est comme ça.

hanoi_stack_r2.py


class hanoi:
    
   def __init__(self,n):
         self.tower = {"A": [*range(n, 0, -1)], "B": [], "C": []}

   def view(self):
       for name,value in self.tower.items():
           print(f"{name} = {value}")
   
   def move(self,n,a,b,c):
       if n>1:
           hanoi.move(self,n-1,a,c,b)
       print(f"{n}À{a}De{c}Quoi")
       self.tower[c].append(self.tower[a].pop())
       hanoi.view(self)           
       if n>1:
           hanoi.move(self,n-1,b,a,c)
           
if __name__ =="__main__":
    num = int(input("enter: "))
    test = hanoi(num)
    test.move(num,"A","B","C")

Merci à @shiracamus pour l'opportunité d'étudier m (_ _) m

Recommended Posts

Défiez la tour de Hanoi avec recurs + stack
Défiez la tour de Hanoi avec récurrence
Bilan du premier défi du machine learning avec Keras
Votre URL n'a pas répondu avec la valeur du paramètre de défi.
Alignez la taille de la barre de couleurs avec matplotlib
Vérifier l'existence du fichier avec python
La troisième nuit de la boucle avec pour
La deuxième nuit de la boucle avec pour
Compter le nombre de caractères avec écho
L'histoire de l'apprentissage profond avec TPU
Remarque: préparez l'environnement de CmdStanPy avec docker
Préparer l'environnement d'exécution de Python3 avec Docker
Mathématiques Todai 2016 résolues avec Python
[Note] Exportez le html du site avec python.
Augmentez la taille de la police du graphique avec matplotlib
Calculez le nombre total de combinaisons avec python
Vérifiez la date du devoir de drapeau avec Python
Éliminez les inconvénients du widget QDock avec PySide
Renommer la balise avec un espace de noms en lxml
Remplissez la largeur du bloc-notes Jupyter pour remplir le navigateur
Prédisez le deuxième tour de l'été 2016 avec scikit-learn
Vider le contenu de la base de données redis avec lua
Découvrez le jour par date / heure
La base de la théorie des graphes avec l'animation matplotlib
Visualisez le comportement de l'algorithme de tri avec matplotlib
Convertir le code de caractère du fichier avec Python3
[Python] Déterminez le type d'iris avec SVM
Extraire le tableau des fichiers image avec OneDrive et Python
Essayez de résoudre le livre des défis de programmation avec python3
Ajouter des attributs d'objets de classe avec une instruction for
Coordonnées les plus à droite de l'étiquette faite avec tkinter
Apprenez Nim avec Python (dès le début de l'année).
Calculer la somme des valeurs uniques par tabulation croisée des pandas
Jouez avec l'implémentation de l'interface utilisateur de Pythonista 3 [Super Super Primer]
Calculez la valeur totale de plusieurs colonnes avec awk
Pipeline ML: met en évidence les défis de l'extraction manuelle de fonctionnalités
L'histoire du partage de l'environnement pyenv avec plusieurs utilisateurs
Détruire l'expression intermédiaire de la méthode sweep avec Python
Prenez des captures d'écran LCD avec Python-LEGO Mindstorms
Visualisez la gamme d'insertions internes et externes avec python
Calculer le coefficient de régression d'une analyse de régression simple avec python
Prenez la valeur du thermo-hygromètre SwitchBot avec Raspberry Pi
Référence et modification de la limite supérieure récursive Python
Défiez l'analyse des composants principaux des données textuelles avec Python
Prédire le nombre de personnes infectées par COVID-19 avec Prophet
Changer les valeurs du thermo-hygromètre Bot avec Raspberry Pi
Découvrez l'emplacement des packages installés avec pip
Prédire le sexe des utilisateurs de Twitter grâce à l'apprentissage automatique
Essayez d'obtenir le contenu de Word avec Golang
Visualisez le vocabulaire caractéristique d'un document avec D3.js
J'ai mesuré les performances d'un million de documents avec mongoDB
Préparation de l'environnement d'exécution de PyTorch avec Docker Novembre 2019
Lisez la puissance du compteur intelligent avec M5StickC (édition BP35C0-J11-T01)
Gérez le numéro de version du package de requirements.txt avec pip-tools
Résumé du flux de base de l'apprentissage automatique avec Python
Obtenez l'état de fonctionnement de JR West avec Python
Visualisez le statut d'appréciation des œuvres d'art avec OpenCV