汉诺塔问题(分治+源码+动画演示)
漢諾塔問題(分治+源碼+動(dòng)畫演示)
漢諾塔問題源自印度一個(gè)古老的傳說,印度教的“創(chuàng)造之神”梵天創(chuàng)造世界時(shí)做了 3 根金剛石柱,其中的一根柱子上按照從小到大的順序摞著 64 個(gè)黃金圓盤。梵天命令一個(gè)叫婆羅門的門徒將所有的圓盤移動(dòng)到另一個(gè)柱子上,移動(dòng)過程中必須遵守以下規(guī)則:
每次只能移動(dòng)柱子最頂端的一個(gè)圓盤;
每個(gè)柱子上,小圓盤永遠(yuǎn)要位于大圓盤之上;
圖 1 給您展示了包含 3 個(gè)圓盤的漢諾塔問題:
圖 1 漢諾塔問題
一根柱子上摞著 3 個(gè)不同大小的圓盤,那么在不違反規(guī)則的前提下,如何將它們移動(dòng)到另一個(gè)柱子上呢?圖 2 給大家提供了一種實(shí)現(xiàn)方案:
圖 2 漢諾塔問題的解決方案
漢諾塔問題中,3 個(gè)圓盤至少需要移動(dòng) 7 次,移動(dòng) n 的圓盤至少需要操作 2n-1 次。
在漢諾塔問題中,當(dāng)圓盤個(gè)數(shù)不大于 3 時(shí),多數(shù)人都可以輕松想到移動(dòng)方案,隨著圓盤數(shù)量的增多,漢諾塔問題會(huì)越來越難。也就是說,圓盤的個(gè)數(shù)直接決定了漢諾塔問題的難度,解決這樣的問題可以嘗試用分治算法,將移動(dòng)多個(gè)圓盤的問題分解成多個(gè)移動(dòng)少量圓盤的小問題,這些小問題很容易解決,從而可以找到整個(gè)問題的解決方案。
分治算法解決漢諾塔問題
為了方便講解,我們將 3 個(gè)柱子分別命名為起始柱、目標(biāo)柱和輔助柱。實(shí)際上,解決漢諾塔問題是有規(guī)律可循的:
當(dāng)起始柱上只有 1 個(gè)圓盤時(shí),我們可以很輕易地將它移動(dòng)到目標(biāo)柱上;
當(dāng)起始柱上有 2 個(gè)圓盤時(shí),移動(dòng)過程如下圖所示:
圖 3 移動(dòng)兩個(gè)圓盤
移動(dòng)過程是:先將起始柱上的 1 個(gè)圓盤移動(dòng)到輔助柱上,然后將起始柱上遺留的圓盤移動(dòng)到目標(biāo)柱上,最后將輔助柱上的圓盤移動(dòng)到目標(biāo)柱上。
通過分析以上 3 種情況的移動(dòng)思路,可以總結(jié)出一個(gè)規(guī)律:對(duì)于 n 個(gè)圓盤的漢諾塔問題,移動(dòng)圓盤的過程是:
將起始柱上的 n-1 個(gè)圓盤移動(dòng)到輔助柱上;
將起始柱上遺留的 1 個(gè)圓盤移動(dòng)到目標(biāo)柱上;
將輔助柱上的所有圓盤移動(dòng)到目標(biāo)柱上。
由此,n 個(gè)圓盤的漢諾塔問題就簡(jiǎn)化成了 n-1 個(gè)圓盤的漢諾塔問題。按照同樣的思路,n-1 個(gè)圓盤的漢諾塔問題還可以繼續(xù)簡(jiǎn)化,直至簡(jiǎn)化為移動(dòng) 3 個(gè)甚至更少圓盤的漢諾塔問題。
如下為分治算法解決漢諾塔問題的偽代碼:
// num 表示移動(dòng)圓盤的數(shù)量,source、target、auxiliary 分別表示起始柱、目標(biāo)柱和輔助柱 hanoi(num ,
source , target , auxiliary):
if num == 1: // 如果圓盤數(shù)量?jī)H有 1 個(gè),則直接從起始柱移動(dòng)到目標(biāo)柱
print(從 source 移動(dòng)到 target)
else:
// 遞歸調(diào)用 hanoi 函數(shù),將 num-1 個(gè)圓盤從起始柱移動(dòng)到輔助柱上,整個(gè)過程的實(shí)現(xiàn)可以借助目標(biāo)柱
hanoi(num-1 , source , auxiliary , target)
// 將起始柱上剩余的最后一個(gè)大圓盤移動(dòng)到目標(biāo)柱上
print(從 source 移動(dòng)到 target)
// 遞歸調(diào)用 hanoi 函數(shù),將輔助柱上的 num-1 圓盤移動(dòng)到目標(biāo)柱上,整個(gè)過程的實(shí)現(xiàn)可以借助起始柱
hanoi(n-1 , auxiliary , target , source)
漢諾塔問題的代碼實(shí)現(xiàn)
根據(jù)偽代碼,我們?yōu)榇蠹揖帉懞昧讼鄳?yīng)的 C 語言、Java 以及 Python 程序。
如下是解決漢諾塔問題的 C 語言程序:
#include <stdio.h> void hanoi(int num, char sou, char tar,char aux) {//統(tǒng)計(jì)移動(dòng)次數(shù)static int i = 1;//如果圓盤數(shù)量?jī)H有 1 個(gè),則直接從起始柱移動(dòng)到目標(biāo)柱if (num == 1) {printf("第%d次:從 %c 移動(dòng)至 %c\n", i, sou, tar);i++;}else {//遞歸調(diào)用 hanoi() 函數(shù),將 num-1 個(gè)圓盤從起始柱移動(dòng)到輔助柱上hanoi(num - 1, sou, aux, tar);//將起始柱上剩余的最后一個(gè)大圓盤移動(dòng)到目標(biāo)柱上printf("第%d次:從 %c 移動(dòng)至 %c\n", i, sou, tar);i++;//遞歸調(diào)用 hanoi() 函數(shù),將輔助柱上的 num-1 圓盤移動(dòng)到目標(biāo)柱上hanoi(num - 1, aux, tar, sou);} } int main() {//以移動(dòng) 3 個(gè)圓盤為例,起始柱、目標(biāo)柱、輔助柱分別用 A、B、C 表示hanoi(3, 'A', 'B', 'C');return 0; }如下是解決漢諾塔問題的 Java 程序:
public class Demo {// 統(tǒng)計(jì)移動(dòng)次數(shù)public static int i = 1;public static void hanoi(int num, char sou, char tar, char sux) {// 如果圓盤數(shù)量?jī)H有 1 個(gè),則直接從起始柱移動(dòng)到目標(biāo)柱if (num == 1) {System.out.println("第" + i + "次:從" + sou + "移動(dòng)到" + tar);i++;} else {// 遞歸調(diào)用 hanoi() 函數(shù),將 num-1 個(gè)圓盤從起始柱移動(dòng)到輔助柱上hanoi(num - 1, sou, sux, tar);// 將起始柱上剩余的最后一個(gè)大圓盤移動(dòng)到目標(biāo)柱上System.out.println("第" + i + "次:從" + sou + "移動(dòng)到" + tar);i++;// 遞歸調(diào)用 hanoi() 函數(shù),將輔助柱上的 num-1 圓盤移動(dòng)到目標(biāo)柱上hanoi(num - 1, sux, tar, sou);}}public static void main(String[] args) {// 以移動(dòng) 3 個(gè)圓盤為例,起始柱、目標(biāo)柱、輔助柱分別用 A、B、C 表示hanoi(3, 'A', 'B', 'C');} }如下是解決漢諾塔問題的 Python 程序:
#記錄移動(dòng)次數(shù) i = 1 def hanoi(num,sou,tar,aux):global iif num==1:print("第%d次:從 %c 移動(dòng)至 %c" % (i, sou, tar))i=i+1else:#遞歸調(diào)用 hanoi() 函數(shù),將 num-1 個(gè)圓盤從起始柱移動(dòng)到輔助柱上hanoi(num - 1, sou, aux, tar)#將起始柱上剩余的最后一個(gè)大圓盤移動(dòng)到目標(biāo)柱上print("第%d次:從 %c 移動(dòng)至 %c" % (i, sou, tar))i=i+1#遞歸調(diào)用 hanoi() 函數(shù),將輔助柱上的 num-1 圓盤移動(dòng)到目標(biāo)柱上hanoi(num - 1, aux, tar, sou) #以移動(dòng) 3 個(gè)圓盤為例,起始柱、目標(biāo)柱、輔助柱分別用 A、B、C 表示 hanoi(3, 'A', 'B', 'C');以上程序的執(zhí)行結(jié)果均為:
第1次:從 A 移動(dòng)至 B
第2次:從 A 移動(dòng)至 C
第3次:從 B 移動(dòng)至 C
第4次:從 A 移動(dòng)至 B
第5次:從 C 移動(dòng)至 A
第6次:從 C 移動(dòng)至 B
第7次:從 A 移動(dòng)至 B
總結(jié)
以上是生活随笔為你收集整理的汉诺塔问题(分治+源码+动画演示)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 五天拼出一款提词器软件之一项目立项与准备
- 下一篇: 27、资金管理