【问题标题】:Binary solution for Tower of Hanoi河内塔的二进制解决方案
【发布时间】:2012-09-10 08:54:15
【问题描述】:

我正在阅读Algorithms by Robert Sedgewick

以下是第 213 页的摘录,涉及数字二进制表示中尾随零的数量。

对于河内塔问题,对应关系的含义 使用 n 位数字是该任务的简单算法。我们可以移动 按照以下两个步骤将一个钉子向右堆放,直到完成:

  1. 如果 n 为奇数则将小圆盘向右移动(如果 n 为偶数则向左移动)
  2. 进行不涉及小磁盘的唯一合法移动。

也就是说,我们移动小dsik后,另外两个钉子包含两个 磁盘,一个比另一个小。唯一不涉及的合法举动 小磁盘是将较小的磁盘移动到较大的磁盘上。每一个 其他移动涉及较小的磁盘,原因与每个 其他数字是奇数,并且规则上的每个其他标记都是 最短。

上面的文字并没有进入我的脑海,即使在阅读了来自谷歌信息的各种参考之后。

请帮我举一个简单的例子,例如磁盘 N = 3。Disk3 最大,Disk1 最小,它们需要从 PegA 移动到 PegB。

Disk1
Disk2
Disk3
-------       ------------         ------------
Peg A            Peg B                 Peg C

【问题讨论】:

    标签: algorithm towers-of-hanoi


    【解决方案1】:

    这里首先要注意的是,在这个算法中,第一个钉子被认为在最后一个钉子的右边,最后一个钉子被认为是第一个钉子的左边。

    重复应用列出的两个步骤将导致n 磁盘塔向右移动一个钉子。

    如果n = 3n是奇数,那么这两个动作是:

    1. Disk1 向右移动一个钉子。
    2. 做出唯一合法的举动,不涉及Disk1

    通过重复这些动作给出以下解决方案:

    1. Disk1: PegA -> PegB(将Disk1向右移动一个)
    2. Disk2: PegA -> PegC(仅限合法举动,不涉及Disk1
    3. Disk1: PegB -> PegC(将Disk1向右移动一个)
    4. Disk3: PegA -> PegB(仅限合法举动,不涉及Disk1
    5. Disk1: PegC -> PegA(将Disk1向右移动一个)
    6. Disk2: PegC -> PegB(仅限合法举动,不涉及Disk1
    7. Disk1: PegA -> PegB(将Disk1向右移动一个)

    当他写“与n位数字的对应关系”时,Sedgewick指的是你在解决方案的步骤k中移动的磁盘是与最少对应的磁盘k 的二进制表示中的重要 1 位。即对于n = 3

    step | bits | disk
    ------------------
      1  |  001 |  1
      2  |  010 |  2
      3  |  011 |  1
      4  |  100 |  3
      5  |  101 |  1
      6  |  110 |  2
      7  |  111 |  1
    

    【讨论】:

    • 作者所说的“每个其他移动都涉及较小的磁盘,原因与其他所有数字都是奇数并且规则上的所有其他标记最短一样”是什么意思。 ?
    • @venkysmarty 查看更新的答案。他只是说,由于每个奇数的最低有效位都是1,并且每个第二个数字都是奇数,因此每秒钟移动都会涉及磁盘1。
    • 感谢您的详细解释。我这里还有一个问题“在我们移动小 dsik 之后,另外两个 peg 包含两个磁盘,一个比另一个小。”作者在这里的意思是什么假设如果我们有 N=4 其他两个 peg 包含超过 2 个磁盘我是马上到这里?
    • @venkysmarty 可能措辞不佳,但他的意思是“两个磁盘”是两个钉中的每一个上的顶部磁盘。这并不完全准确,因为有时两个钉子中的一个是空的,但他的意思是对于任何两个钉子AB,要么“将A 的顶部磁盘移动到B " "将B 的顶部磁盘移动到A" 将被允许,但绝不允许两者兼而有之。当然,除非两个钉子都是空的。
    【解决方案2】:

    这个特定问题的解决方案是:将Disk1 移动到Peg B,将Disk2 移动到Peg C,将Disk1 移动到Peg C,将Disk3 移动到Peg B,移动@ 987654329@ 到 Peg A,移动 Disk2Peg B,移动 Disk1Peg B。完成。

    【讨论】:

      【解决方案3】:

      如果这对任何人都有帮助,我在这里用 python 编写了一个完整的解决方案:https://github.com/goblinhack/towers-of-hanoi

      #!/usr/bin/env python
      #
      # The way to solve this is quite simple but does differ slightly for N = odd or even numbers of rings.
      # 
      # At each move you do either a) or b):
      # 
      # a) move the "1" value to the peg to the right, wrapping around to the first peg if needed
      # 
      # b) make the only other legal move
      # 
      # And then repeat either a) or b) for (2 ^ numrings) - 1.
      # 
      # So for N=3, you would do the above steps 7 times.
      # 
      # The catch that I alluded to earlier is that for N == odd (3,5,...), you will need to repeat this
      # entire algorithm one more time as the above will only move the rings one peg to the right. 
      #
      import sys
      
      #
      # Print the tower so we can check our progress
      #
      def print_tower(pegs, nrings):
          npegs = len(pegs)
          for y in range(0, nrings):
              h = nrings - y
              for x in range(0, npegs):
                  if len(pegs[x]) >= h:
                      sys.stdout.write(str(pegs[x][len(pegs[x]) - h]) + " ")
                  else:
                      sys.stdout.write("| ")
              print("")
          print("-----")
      
      def solve_tower(nrings, npegs):
          pegs = []
          for peg in range(0, npegs):
              pegs.append([])
      
          #
          # push the nrings on
          #
          for i in range(0, nrings):
              pegs[0].append(i + 1)
      
          #
          # For N == odd numbers we will need to repeat this twice
          #
          for tries in range(0, 1 + nrings % 2):
              print_tower(pegs, nrings)
              move_peg_one_right = True
      
              #
              # Repeat the steps a) or b) for 2^N-1 times
              #
              for moves in range(0, (1 << nrings) - 1):
                  #
                  # step a)
                  #
                  if move_peg_one_right:
                      for peg in range(0, npegs):
                          if len(pegs[peg]):
                              if pegs[peg][0] == 1:
                                  next_peg = (peg + 1) % npegs
                                  pegs[next_peg].insert(0, pegs[peg].pop(0))
                                  print("Moving value 1 from peg {} to peg {}\n".format(peg + 1, next_peg + 1))
                                  break
                  else:
                      #
                      # step b)
                      #
                      moved_a_ring = False
                      for peg in range(0, npegs):
                          #
                          # Look for a ring on a peg to move
                          #
                          if len(pegs[peg]):
                              value = pegs[peg][0]
                              #
                              # Don't move the ring value "1" as we move that in a)
                              #
                              if value != 1:
                                  for next_peg in range(0, npegs):
                                      #
                                      # The next peg is the one to the right of this peg. If we reach the last peg then we
                                      # need to move to the first peg.
                                      #
                                      next_peg = (peg + next_peg) % npegs
      
                                      #
                                      # Don't move to the same peg; that would be silly
                                      #
                                      if next_peg == peg:
                                          continue
      
                                      #
                                      # If the destination peg is empty, move there
                                      #
                                      if not len(pegs[next_peg]):
                                          pegs[peg].pop(0)
                                          pegs[next_peg].insert(0, value)
                                          moved_a_ring = True
                                          print("Moving value {} from peg {} to empty peg {}\n".format(value, peg + 1, next_peg + 1))
                                          break
                                      elif value < pegs[next_peg][0]:
                                          #
                                          # Else if the destination peg has a lower value, move there
                                          #
                                          pegs[peg].pop(0)
                                          pegs[next_peg].insert(0, value)
                                          moved_a_ring = True
                                          print("Moving < value {} from peg {} to peg {} dest {}\n".format(value, peg + 1, next_peg + 1, pegs[next_peg][0]))
                                          break
                          if moved_a_ring:
                              break
      
                      if not moved_a_ring:
                          print("Error, failed to move")
                          sys.exit(1)
      
                  print_tower(pegs, nrings)
      
                  #
                  # Alternate between a) and b)
                  #
                  move_peg_one_right = not move_peg_one_right
      
              print("Finished pass\n")
      
      nrings = 3
      npegs = 3
      solve_tower(nrings, npegs)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-08-31
        • 1970-01-01
        • 1970-01-01
        • 2015-10-08
        • 1970-01-01
        • 2016-03-19
        • 1970-01-01
        • 2016-05-25
        相关资源
        最近更新 更多