這一次,我來學習如何解決一個著名的問題:漢諾塔問題
總所周知,漢諾塔問題的主要提干是:
漢諾塔(又稱河內塔)問題是源於印度一個古老傳說的益智玩具。大梵天創造世界的時候做了三根金剛石柱子,在一根柱子上從下往上按照大小順序摞着64片黃金圓盤。大梵天命令婆羅門把圓盤從下面開始按大小順序重新擺放在另一根柱子上。並且規定,在小圓盤上不能放大圓盤,在三根柱子之間一次只能移動一個圓盤。
根據題意,我們下意識會覺得這個題目實際上很難,因為它加上了一些限定條件:三根柱子間一次只能移動一個原盤,自始至終大圓盤不能在小圓盤上等等……
我們最終的任務是把最左邊的柱子上的圓盤移動到最右邊去,這顯然需要一個遞歸的函數去實現……
單純地,我們通過算法可以將一個漢諾塔的解決方案編寫出來:
def move(n,a,b,c):
if n==1: #當只有一個圓盤時只需從最左端移向最右端
print(a,'-->',c) #面板可視化,可以通過列舉圖標表現移動的步驟形式
else:
move(n-1,a,c,b) #將前n-1個盤子從a移動到b上
move(1,a,b,c) #將最底下的最后一個盤子從a移動到c上
move(n-1,b,a,c) #將b上的n-1個盤子移動到c上
move(3,'A','B','C')
效果:
Wow!就是這么簡單,兩三行的代碼就可以解決這個問題,這就是代碼之美,仔細看這幾行代碼,原來我們只是將我們希望的移動結果以及移動規則告訴計算機,就可以解決這個“我們認為好像很難的題目”!
那么,我們解決了算法的部分,那要如何將它像現實中那樣可視化表現出來呢?
我們想到了turtle庫!啊~好親切啊~
沒錯!就是用turtle庫將我們的各種元素“柱子”,“盤子”給畫出來!,這當然不是什么難事,最重要的是如何將它們的移動與代碼合成起來,用上述代碼指導它們的移動(move)?
emmmmm……好吧,也許還是因為我的能力比較有限,目前比較難以實現!
通過網上找了一些解決的方法資料,結合自己所學,我通過數據結構中的“棧”的概念,結合turtle庫
我們寫下了以下代碼:
import turtle
class Stack: #宏觀定義算法用法
def __init__(self):
self.items = []
def isEmpty(self):
return len(self.items) == 0
def push(self, item):
self.items.append(item)
def pop(self):
return self.items.pop()
def peek(self):
if not self.isEmpty():
return self.items[len(self.items) - 1]
def size(self):
return len(self.items)
def drawpole_3(): #畫出漢諾塔的poles
t = turtle.Turtle()
t.hideturtle()
def drawpole_1(k):
t.up()
t.pensize(10)
t.pencolor('blue')
t.speed(100)
t.goto(200*(k-1), 100)
t.down()
t.goto(200*(k-1), -100)
t.goto(200*(k-1)-20, -100)
t.goto(200*(k-1)+20, -100)
drawpole_1(0)#畫出漢諾塔的poles[0]
drawpole_1(1)#畫出漢諾塔的poles[1]
drawpole_1(2)#畫出漢諾塔的poles[2]
def creat_plates(n) :#制造n個盤子
plates=[turtle.Turtle() for i in range(n)]
for i in range(n):
plates[i].up()
plates[i].hideturtle()
plates[i].shape("square")
plates[i].shapesize(1,8-i)
plates[i].goto(-200,-90+20*i)
plates[i].showturtle()
return plates
def pole_stack(): #制造poles的棧(由於每次只能移動一個盤子且盤子只能從最上面開始拿,故用棧)
poles=[Stack() for i in range(3)]
return poles
def moveDisk(plates,poles,fp,tp):#把poles[fp]頂端的盤子plates[mov]從poles[fp]移到poles[tp](其實就是上述的第一個的最基本的那個算法)
mov=poles[fp].peek()
plates[mov].goto((fp-1)*200,150)
plates[mov].goto((tp-1)*200,150)
l=poles[tp].size() #確定移動到底部的高度(恰好放在原來最上面的盤子上面)
plates[mov].goto((tp-1)*200,-90+20*l)
def moveTower(plates,poles,height,fromPole, toPole, withPole):#遞歸放盤子
if height >= 1:
moveTower(plates,poles,height-1,fromPole,withPole,toPole)
moveDisk(plates,poles,fromPole,toPole)
poles[toPole].push(poles[fromPole].pop())
moveTower(plates,poles,height-1,withPole,toPole,fromPole)
myscreen=turtle.Screen()
drawpole_3()
n=int(input("請輸入漢諾塔的層數並回車:\n"))
plates=creat_plates(n)
poles=pole_stack()
for i in range(n):
poles[0].push(i)
moveTower(plates,poles,n,0,2,1)
myscreen.exitonclick()
此時我們輸入盤子的數量:
於是乎,回車鍵以后我們就可以得出下面的動畫啦~
cool!
通過封裝多個不同功能的python代碼,結合多個方法就可以實現這樣看似復雜的實現!
python真是越來越有趣了~