【问题标题】:Towers of Hanoi non-recursive function河内塔非递归函数
【发布时间】:2018-02-21 18:49:06
【问题描述】:

我正在尝试弄清楚如何在下面的函数hanoi_2 中实现河内塔问题的非递归算法,但我不知道如何继续......

它抛出一个错误:“不能从空列表中弹出”。当我输入一个奇数时,它会以某种方式工作,但是,当第三轮通过时,事情就出错了。当输入偶数作为光盘数时,程序甚至不会启动。

怎么了?

from turtle import *
from tkinter import *  # used for the dialog box
from tkinter.simpledialog import askinteger  # used for the dialog box
from tkinter import ttk  # used for the progress bar
import time  # used for time-related functions (in pause)
import pickle  # used to save an object to a file

class Disc(Turtle):
    def __init__(self, n):
        Turtle.__init__(self, shape="square", visible=False)
        self.pu()
        self.shapesize(1.5, n*1.5, 2)  # square-->rectangle
        self.fillcolor(n/10., 0, 1-n/10.)
        self.st()
        self.speed(11-n)  # sets the speed of movement of the rectangles (the bigger, the slower)
        self.moves = 0  # stores the number of times the disc is moved

class Tower(list):
    """Hanoi tower, a subclass of built-in type list"""
    def __init__(self, x):
        """create an empty tower. x is x-position of peg"""
        self.x = x

    def push(self, d):
        d.setx(self.x)
        d.sety(-150+34*len(self))
        d.clear()
        d.write("Moved %s times" %(str(d.moves)), align="left", font=("Courier", 16, "bold"))
        d.moves += 1  # increments the number of moves each time the disc is moved
        self.append(d)

    def pop(self):
        d = list.pop(self)
        d.sety(150)
        return d

def hanoi(n, from_, with_, to_):
    global moves
    global ans
    clear()
    if n > 0:
        hanoi(n-1, from_, to_, with_)
        moves += 1  # amount of total moves is incremented
        to_.push(from_.pop())
        hanoi(n-1, with_, from_, to_)
    sety(-255)
    write("Total moves: %s" % (moves), align="center", font=("Courier", 16, "bold"))
    sety(-320)
    progress_bar(ans)  # calls progress bar function

def hanoi_2(n, A, B, C):
    global moves
    clear()
    if n%2==0:
        B=C
        C=A
        A=B
    for i in range(1,(2**n)-1):
        if i%3==1:
            C.push(A.pop())
        if i%3==2:
            B.push(A.pop())
        if i%3==0:
            B.push(C.pop())

【问题讨论】:

    标签: python python-3.x function towers-of-hanoi non-recursive


    【解决方案1】:

    偶数磁盘的问题是堆栈交换不正确:您似乎想要循环三个堆栈(您以错误的方式执行此操作,因为您丢失了对原始 B 列表的引用),而实际上你只需要交换 B 和 C 堆栈,你可以这样做:

    B, C = C, B
    

    算法的问题在于,尽管您拥有正确的两个堆栈(基于i%3),但您仍然必须确定两个所涉及堆栈中的哪一个是给予者,哪一个是接受者,因为这并不总是相同!最好为此编写一个函数,该函数需要两个堆栈并确定两个可能的“方向”中的哪一个是有效的,然后执行该移动:

    def validMove(A, B):
        if not len(A): 
            A.push(B.pop())
        elif not len(B):
            B.push(A.pop())
        elif A[-1] > B[-1]:
            A.push(B.pop())
        else:
            B.push(A.pop())
    

    现在主算法将如下所示:

    for i in range(1,2**n):
        if i%3==1:
            validMove(A, C)
        if i%3==2:
            validMove(A, B)
        if i%3==0:
            validMove(B, C)
    

    【讨论】:

    • 为什么我们用偶数个磁盘交换 B 和 C 堆栈?主算法中i%3背后的原因是什么?
    • @Brayoni,这就是 Hanoi 算法的工作原理。这是一种平价。如果您不交换 B 和 C 堆栈,算法最终会将圆盘带到 B 而不是 C。i%3 将确保在每次移动时您将排除不同的堆栈(从移动中):首先排除堆栈 B,然后是堆栈 C,然后是堆栈 A,然后是堆栈 B,然后是堆栈 C,......等等。 i%3 有助于做到这一点。
    【解决方案2】:

    错误很少。首先,交换是不正确的。替换后,AB 引用同一个对象。要么使用临时变量,要么使用 Python 语法:B, C, A = C, A, B。其次,这种替换应该在for 循环内完成,而不是之前。看看递归版本,你每次都会改变塔的顺序。

    我是用手机写的,所以我无法为你解决,但祝你好运!:-)

    【讨论】:

      【解决方案3】:

      下面是一个递归和等效的迭代解决方案。堆栈保存调用的顺序及其状态。在这种情况下,堆栈上有一个状态。

      #recursive solution
      def tower(numRings):
          def tower1(numRings,fromPeg,toPeg,usePeg):
              if numRings > 0: #A
                  tower1(numRings-1,fromPeg,usePeg,toPeg) #B
                  result.append((fromPeg,toPeg)) #C
                  tower1(numRings-1,usePeg,toPeg,fromPeg) #D
          result = []
          tower1(numRings,0,1,2)
          return result
      
      #iterative solution
      def tower(numRings):
          result = []
          stk = []
          def tower1(numRings):
              In, To = 0, 1
              stk.append((In,numRings,0,1,2))
              while stk:
                  state,numRings,fromPeg,toPeg,usePeg = stk.pop()
                  if state == In:
                      if numRings != 0: #push down to 1 numRing #A
                          stk.append((To,numRings,fromPeg,toPeg,usePeg)) #B save state
                          stk.append((In,numRings-1,fromPeg,usePeg,toPeg)) 
                  elif state == To:
                      result.append((fromPeg,toPeg)) #C
                      stk.append((In,numRings-1,usePeg,toPeg,fromPeg)) #D
                  else:
                      print 'Error: logic'
                      return result
          tower1(numRings)
          return result
      
      a = [1,2,3,4]
      for n in a:
          print 'rings',n
          print tower(n)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-09-11
        • 1970-01-01
        • 2023-03-12
        • 2013-08-28
        • 2017-02-04
        • 2016-01-27
        • 1970-01-01
        相关资源
        最近更新 更多