1. 程式人生 > 實用技巧 >迭代演算法經典問題之漢諾塔

迭代演算法經典問題之漢諾塔

漢諾塔的傳說

相傳在世界中心貝拿勒斯(在印度北部)的聖廟裡,一塊黃銅板上插著三根寶石針。印度教的主神梵天在創造世界的時候,在其中一根針上從下到上地穿好了由大到小的64片金片,這就是所謂的漢諾塔。不論白天黑夜,總有一個僧侶在按照下面的法則移動這些金片:一次只移動一片,不管在哪根針上,小片必須在大片上面。僧侶們預言,當所有的金片都從梵天穿好的那根針上移到另外一根針上時,世界就將在一聲霹靂中消滅,而梵塔、廟宇和眾生也都將同歸於盡。

演算法分析

該問題實際上是一個非常典型的迭代問題,所謂迭代問題就是原問題拆分的子問題實質上仍然是原問題,此外,每個迭代問題都應該有一個base case,即在此情況下停止迭代。

用迭代的角度來看漢諾塔問題:

  • 把n個金片從第一個銀針上全部轉移到第三個銀針上的操作定義為函式Transfer(n,start=1,end=3)。
  • 把n-1個金片從第一個銀針上全部轉移到第三個銀針上為函式Transfer(n-1,start=1,end=3)。
  • Transfer(n-1,start=1,end=3)與Transfer(n,start=1,end=3)屬於一類問題。
  • Transfer(n,start=1,end=2)與Transfer(n-1,start=1,end=3)有聯絡,即在n-1個金片全部從第一根到第三根後,只需將第n個金片從第一根轉移到第二根,然後再把其他的n-1個金片放到它上面,即發生了Transfer(n-1,start=3,end=2),最後得到Transfer(n,start=1,end=2)。
  • Base case就是n=1時,直接將n=1的金片從1移到3.

Python程式碼實現

def Transfer(n,start=1,end=3):
    if n:
        Transfer(n-1,start,6-start-end) # 將n-1個金片從start轉移到6-start-end
        print('Move disk %d from rod %d to rod %d  '%(n, start,end))
        Transfer(n-1,6-start-end,end)# 將n-1個金片從6-start-end轉移到end

output:

Transfer(3)
Move disk 1 from rod 1 to rod 3  
Move disk 2 from rod 1 to rod 2  
Move disk 1 from rod 3 to rod 3  
Move disk 3 from rod 1 to rod 3  
Move disk 1 from rod 2 to rod 1  
Move disk 2 from rod 2 to rod 3  
Move disk 1 from rod 1 to rod 3 
Transfer(4)
Move disk 1 from rod 1 to rod 2  
Move disk 2 from rod 1 to rod 3  
Move disk 1 from rod 2 to rod 3  
Move disk 3 from rod 1 to rod 2  
Move disk 1 from rod 3 to rod 0  
Move disk 2 from rod 3 to rod 3  
Move disk 1 from rod 0 to rod 3  
Move disk 4 from rod 1 to rod 3  
Move disk 1 from rod 2 to rod 3  
Move disk 2 from rod 2 to rod 1  
Move disk 1 from rod 3 to rod 3  
Move disk 3 from rod 2 to rod 3  
Move disk 1 from rod 1 to rod 2  
Move disk 2 from rod 1 to rod 3  
Move disk 1 from rod 2 to rod 3 

需要注意幾點:

  • 將n-1個金片從start轉移到6-start-end,這裡start不能用1代替,因為在迭代中start是動態變動的,而end=6-start-end則是動態的表示是除了start和end外的寶石針,6=1+2+3。
  • 在將n-1個金片全部轉移到6-start-end後,將第n個金片轉移到end,因此可以用print輸出此時是將哪個金片從哪裡移動到哪裡,也可以理解為此時將第n個金片移動到了end。
  • print輸出後(將第n個金片移動到了end後),將n-1個金片從6-start-end轉移到既定的end。