漢諾塔問題是一個經典的「重複問題「(recurrent problem),解法也中所周知,最少移動步驟是2^n - 1。算法
然而,我發現,對這個問題進行進一步的研究也是挺有意思的。code
本篇博客目前闡述三個Hanoi相關的三個問題(基本問題,擴展問題,變種問題)。博客
基本問題:數學
n個盤子,ABC三個地點,將A上的n個盤子移動到C上。最少的步驟是多少?效率
AC[n] = AB[n-1] + AC[1] + BC[n-1]擴展
由於AC[n] = BC[n] = AB[n] := T(n)二進制
因此以上等式能夠寫成T(n) = T(n-1) + 1 + T(n-1),從而獲得T(n) = 2^n - 1方法
擴展問題移動
由基本問題的推導步驟,咱們知道,要在2^n - 1步內將n個盤子從A移動到C,那麼每一步都是固定的!時間
由此,產生如下問題:
通過k步移動後,每一個盤子的狀態是什麼?即,每一個盤子是在A,B仍是C上?
解法1: 對於這個問題,咱們固然能夠模擬K步移動來解的答案,可是,這是很是沒有效率的。由於K有可能很大,是2的指數級增加東西,因此,這種解法很是愚蠢!
咱們須要獲得的信息是每一個盤子的狀態,而不是每一步的具體移動步驟和狀態,因此,咱們需求的信息是相對較少的,也就必然有比解法1要好的多的解法。理想情況是O(n)時間複雜度,由於不可能比O(n)更小了,你須要要對看一看每一個盤子。
從基本問題的推導中,咱們能夠看到,漢諾塔問題的解決,不過是在不斷的重複和交換「起始點「 」中間點「 和 「目的點「。咱們以src, med, 和dst來標誌他們。由此,咱們很容易想到,咱們的解法也能夠是「重複"+"交換".
個人思路是先考察簡單狀況,好比盤子是2個,3個的狀況,獲得一個先驗的結論和體會。有興趣的朋友能夠試一下。
在考察完簡單狀況後,結合咱們的大方向"重複"+"交換",咱們很容易想到如下解法(若是你本身動手考察過簡單狀況的話,會比較容易理解):
K = (a[n-1] a[n-2] ... a[1] a[0])的二進制表示. 其中a[i] = 0或者1. (這一步須要花費O(n)時間)
for i <- n-1 to 0
if a[i] == 0
p[i] = src; swap(med, dst);
if a[i] == 1
p[i] = dst; swap(src, med);
結束。
p[n-1] ... p[0]中的值就是各個盤子的狀態,算法時間複雜度爲O(n).
變種問題:
變種問題是,若是盤子的移動只能從A->B->C或者C->B->A,AC之間不能直接移動盤子,這個漢諾塔的問題會怎麼樣呢?咱們一樣考察以上兩個問題,即最少步驟和第K步狀態。
最小步驟的推導方法和基本漢諾塔問題一致,在此不贅述了,能夠獲得結論是3^n - 1.
關於第K步狀態,有點不同。若是咱們和基本漢諾塔問題的K步問題同樣的方法來考察這個問題的話,是能夠獲得結論的,可是,思路複雜而且耗時長(不信的朋友能夠試試)。
如下介紹一種nb的思路來解決這個問題,這個思路我本身沒想出來,是參考了一些資料才獲得的。
用3進制Gray Code來模擬移動過程!!!!!
朋友!你能想到麼?增長了附加的條件後,數學模型居然更加簡單了!
因而移動過程就是Gray Code從00000 增長到 222222 , 因而恰好能夠用0 1 2來表徵狀態!!!有木有!!!
第K步的狀態能夠用3進制來表示後,設一個reverse flag(表徵某位是從0-1-2仍是2-1-0)。因而即可以用簡單的數學模型+重複+[每步reverse flag]來解決問題!時間複雜度爲O(n).
3進制gray code!!
路漫漫其修遠兮,吾將上下而求索!