基于數(shù)學(xué)推導(dǎo)&編程遞歸解決琺露珊角色邀約任務(wù)“堆棧塔”(漢諾塔)最少步數(shù)問題

????琺露珊角色邀約任務(wù)中,有段分支提到了前輩發(fā)現(xiàn)的一種益智機(jī)關(guān)“堆棧塔”?,F(xiàn)實當(dāng)中,堆棧塔的原型其實就是漢諾塔問題(Hanoi?Tower),先來看看游戲劇情里是如何介紹堆棧塔的

????用漢諾塔的模型來解釋玩法:給定3根柱子A,B,C,初始有n個圓環(huán)(記為1至n號,由小到大排序)在A上,最終目標(biāo)是通過若干步移動,將所有圓環(huán)都移動到B上,且移動的規(guī)則為:
????①1次移動只能1個圓環(huán)(且應(yīng)當(dāng)是A/B/C最上面的圓環(huán))
????②始終要求小號圓環(huán)堆疊在大號圓環(huán)上(形如金字塔形,例如不能將2號圓環(huán)移動到1號圓環(huán)之上)

????下面UP將使用數(shù)學(xué)推導(dǎo)來解釋最少步數(shù)的解法,并用編程解遞歸問題進(jìn)行驗證,最后闡述下本人的一些想法。

一. 數(shù)學(xué)推導(dǎo)
????我們設(shè)圓環(huán)數(shù)為n,將n個圓環(huán)從A全部移到B所需的最少步數(shù)為an
????首先,最簡單的情況,就是僅1個圓環(huán)(n=1)時,只需要把A上的1號環(huán)移動到B即可,最少移動步數(shù)為1,a1=1,如下圖:

????接下來我們考慮n>1的情形:
? ? 如果我們要將所有圓環(huán)移到B,必經(jīng)的一步當(dāng)然是把n號圓環(huán)從A移到B,前提是要把1至n-1號圓環(huán)全部移走,并留出A、B兩個柱子讓第n號圓環(huán)進(jìn)行移動操作。因此,1到n-1號圓環(huán)就只能按金字塔順序堆疊在C上了。如下圖3所示:

????那么怎么從初始狀態(tài)圖1變到圖3的情形呢?不難發(fā)現(xiàn),從圖1到圖3本質(zhì)上只是將第1至n-1號圓環(huán)從A全部移動到C而已,這需要的最少步數(shù)是an-1。說明如果你每步都走最優(yōu)路線,那么圖3就是第an-1步。
????接著上面的操作,我們將第n號圓環(huán)從A移到B,這是第(an-1)+1步,得到下面的圖4:

????到達(dá)圖4的情形后,我們下一步要將剩下的n-1個圓環(huán)全部疊到B上,細(xì)心的同學(xué)已經(jīng)發(fā)現(xiàn),這本質(zhì)上也是將第1至n-1號圓環(huán)從C全部移動到B而已,需要的最少步數(shù)仍然是an-1。完成以后,就達(dá)到我們的目標(biāo)啦↓

? ? 通過上述描述,我們將n層漢諾塔解法分解為3個步驟:
? ? ①將n-1層漢諾塔整體從A移動到C,最少步數(shù)為an-1
????②將第n個圓環(huán)從A移動到B,所需步數(shù)為1
????③將n-1層漢諾塔整體從C移動到B,最少步數(shù)為an-1
? ? 將上述三點的步數(shù)相加,由此求得所需最少步數(shù)的遞推公式:

????根據(jù)遞推公式,可以解得an的表達(dá)式:

? ? 我們不妨代入前8個正整數(shù)試試:

????回到邀約任務(wù)的劇情,可見前面幾位小盆友在玩n=4和5的堆棧塔時,都沒能實現(xiàn)最少步數(shù)。而前輩向旅行者提問的是n=7的情形,運用數(shù)學(xué)推導(dǎo)不難得到答案是127步↓

????眾所周知,2×(2^(n-1)-1) + 1 = 2^(n) -?1,所以公式是沒有問題的↓

????這個游戲還是蠻有趣的,作為益智玩具(機(jī)關(guān))都是不錯的想法,只能說不愧是前輩??

二. 程序編寫(遞歸問題)
????對于進(jìn)修過編程類課程的大學(xué)生來說,漢諾塔應(yīng)該是再經(jīng)典不過的遞歸問題了。上文已經(jīng)通過數(shù)學(xué)推導(dǎo)掌握了規(guī)律,那么就可以通過遞歸算法重構(gòu)漢諾塔模型,然后丟給計算機(jī)來思考就行。
????實現(xiàn)過程也很簡單,我們先構(gòu)建2個函數(shù)↓
????①move函數(shù)

????該函數(shù)表示單獨1次移動的操作,形參src和dest分別表示拿出圓環(huán)和放入圓環(huán)的兩根柱子,也就是將src最上方的圓環(huán)移動到dest上,同時用count記錄1次移動次數(shù)。
????②hanoi函數(shù)

????hanoi函數(shù)是遞歸函數(shù),其算法原理就是先前討論過的三個步驟。當(dāng)輸入層數(shù)n,初始柱src,中間柱medium,目標(biāo)柱dest后,如果n=1,就只需調(diào)用一次move函數(shù)。否則就要拆分成三個步驟:
????(1)把1至n-1號的圓環(huán)從初始柱src移動到medium(注:此時遞歸函數(shù)hanoi中的目標(biāo)柱變成了medium,而中間柱變成了dest)。
????(2)把第n號圓環(huán)從src移動到dest(調(diào)用一次move函數(shù)即可)。
????(3)將剩下的在medium里的n-1層圓環(huán)全部移動到dest(此時遞歸函數(shù)hanoi中初始柱為medium,目標(biāo)柱為dest)
????最后來個實例,我們利用上述2個函數(shù)編寫n=4時的輸出代碼:

????運行一下,可以得到n=4的最少步數(shù)以及每一步的移動方法:

? ? 當(dāng)然,也可以略微修改代碼來輸出每個n對應(yīng)的最少步數(shù):

????任取正整數(shù)n,只需要跟著計算機(jī)的每一步走,就能以最少的步數(shù)完成目標(biāo)。當(dāng)然,hanoi塔畢竟是一款益智游戲,還是自己動手玩比較有意思??

三、對“堆棧塔”命名的一些想法
????原神的文案策劃是懂命名的,因為漢諾塔每根柱子處理圓環(huán)的方式和計算機(jī)術(shù)語中的“堆?!笔窍嗨频模梢粤私庀隆緱!康亩x:

??????說簡單些,就是將若干個元素依次存進(jìn)一個列表里,但是只允許對棧頂元素(最新存入的元素)進(jìn)行插入、刪除等操作,那么這個受限制的線性表就稱為【?!?。
????對于漢諾塔的三根柱子,可以視為三個堆棧,每根柱子最上面的圓環(huán)就是所謂的棧頂元素。因為如果要想移動A柱子上的圓環(huán),有且僅有最上面的圓環(huán)可以取走,同時,如果想要把新的圓環(huán)放進(jìn)A,有且僅有最上面的位置可以堆疊(而不能從中間插入)。
????嚴(yán)格上講,漢諾塔的存放方式比堆棧更加嚴(yán)格,因為漢諾塔還要求大圓環(huán)(高值元素)不能堆疊在小圓環(huán)(低值元素)之上…
????這么一看,用“堆棧塔”來命名,確實是挺合理的嘛?(o゜▽゜)o