蓝桥杯每日积累-深入透析汉诺塔问题

汉诺塔问题是一个神秘的题,今天我们一起来解开它神秘的面纱!
首先请看题
题目描述
汉诺塔是一个古老的数学问题:

有三根杆子A,B,C。A 杆上有 n 个 (n>1) 穿孔圆盘,盘的尺寸由下到上依次变小。要求按下列规则将所有圆盘移至 C 杆:
要求如下:
①每次只能移动一个圆盘;
②大盘不能叠在小盘上面。
提示:可将圆盘临时置于 BB 杆,也可将从 AA 杆移出的圆盘重新移回A杆,但都必须遵循上述两条规则问:如何移?最少要移动多少次?

【解题思路】
汉诺塔问题只有两个要求,第一:每次只能移动最上面一个圆盘;第二:最后的C柱子上盘子应该是从大到小放置,而不是乱放。
根据常识很容易想到盘子的搬运方法,第一步:A柱子上共n个盘子,先将n-1个盘子全部依次放置到B柱子上,然后将A柱子上最大的盘子直接放到C柱子上,最后只需要依次将B柱子上的盘子依次摆放到C柱子上就OK! 这种重复性的搬运操作用计算机肯定能轻松解决,接下来我们只需要考虑用哪种算法便好。那么该使用哪种算法?稍微读一读题,很明显该题暗示我们的是盘子总数已经知道,只需要全部移到目的地。所以,A柱子上的盘子只会越来越少!算法呼之欲出----递归算法,digo搞定!
接下来便直接按照我们的逻辑写搬运的顺序就行,代码如下

#用递归方法解决汉诺塔问题:
#步骤一:将A柱的n-1个盘子移动到B柱
#步骤二:将A柱的最后一个盘子移动到C柱
#步骤三:将B柱的n-1个盘子移动到C柱
move_count=0 #总移动次数
def hanoi(p1,p2,p3,n):#传入三柱和盘子个数
    global move_count
    if n==1:#第二步,如果A柱只剩下一个盘子,则将盘子移动到C柱
        print(p1,"->",p3)
        move_count+=1
    else:
        hanoi(p1,p3,p2,n-1)#第一步,先将A柱n-1个盘子全部移动到B柱
        print(p1,"->",p3)
        hanoi(p2,p1,p3,n-1)#第三步,将B柱n-1个盘子全部移动到C柱
        move_count+=1
hanoi("A","B","C",6)
print(move_count)

通过递归算法,我们简单就输出了运输过程和总的搬运次数,但是这只是思维过程的打印,空间内没有实际数据移动。如何更进一步,实现数据的真实移动? 如此,我们便需要思考该用哪种数据结构存储数据,并且该数据结构的增加和删除顺序符合柱子上盘子的增加和减少。只需要稍微思考,柱子上总是先放进去的盘子后拿出来,也就是后放进去的盘子会先拿出来,类比一下,这不就是栈? 所以,直接用栈存储数据就可以实现盘子的搬运! 注意:算法还是用递归,我们没改变算法啊
【看代码】

#利用堆栈数据结构模拟柱子移动盘子,每一个柱子就是一个堆栈
#先模拟一个栈
class Stack:
   def __init__(self):#初始化栈
      self.items=[]
   def isEmpty(self):
      if len(self.items)==0:
         print("栈为空")
      else:
         print("栈不为空")
   def push(self,iteam):
      self.items.append(iteam)
   def pop(self):
      self.items.pop()
   def top(self):
      return self.items[len(self.items)-1]

#创建三个堆栈表示ABC三根柱子
a=Stack()
b=Stack()
c=Stack()

#count计算移动次数
count=0

#移动盘子
def move(p1,p2):
   global count
   value=p1.top()
   p2.push(p1.top())
   p1.pop()
   count += 1
   if p1==a and p2==b:
      print("A->B,移动的盘子编号为:",value)
   elif p1==a and p2==c:
      print("A->C,移动的盘子编号为:",value)
   elif p1 ==b and p2 ==c:
      print("B->C,移动的盘子编号为:", value)
   elif  p1==b and p2==a:
      print("B->A,移动的盘子编号为:", value)
   elif  p1==c and p2==a:
      print("C->A,移动的盘子编号为:", value)
   elif  p1==c and p2==b:
      print("C->B,移动的盘子编号为:", value)
#给A柱添加需要移动的盘子
n=int(input())
for i in range(n):
   a.push(n-i)

def hanoi(p1,p2,p3,n):
   if n==1:
      move(p1,p3)
   else:
      hanoi(p1,p3,p2,n-1)
      move(p1,p3)
      hanoi(p2,p1,p3,n-1)



hanoi(a,b,c,n)
print("总移动次数是:",count)
a.isEmpty()
b.isEmpty()
c.isEmpty()

蓝桥杯每日积累-深入透析汉诺塔问题
【总结】
有了栈存储数据模拟盘子的移动,我们不但可以知道移动过程和次数,而且还可以知道移动的是哪个盘子!通过最后的判空可以明显知道在存储空间中所有的数据均移动到C柱子上。由此更可知,算法是灵魂,数据结构是骨干,互相配合,相辅相成。

上一篇:C# 监听数据库表的变化(SqlDependency)


下一篇:基于Zedboard的开源软件定义无线电(SDR)设备:Panoradio!