雙重河內塔II

雙重河內塔問題

又稱:雙重漢諾塔問題算法

這是第二篇

這是《具體數學:計算機科學基礎(第2版)》中的一道課後習題
這道題也是挺有意義的,可是百度上一篇C/C++代碼都沒有
看了書的答案,和百度上惟一一篇文章黃大佬的思路,仍是沒看懂
最後仍是本身花了一個晚上推出來思路,而後寫出了b問題的代碼
我打算寫三篇隨筆來說這個問題,這是第二篇spa

雙重河內塔包含 2n 個圓盤,它們有 n 種不一樣的尺寸,每一種尺寸的圓盤有兩個。如一般那樣,要求每次只能移動一個圓盤,且不能把較大的圓盤放在較小的圓盤上面。3d

a 若是相同尺寸的圓盤是相互不可區分的,要把一個雙重塔從一根樁柱移動到另外一根樁柱須要移動多少次?code

b 若是在最後的排列中要把全部一樣尺寸的圓盤恢復成原來的從上到下的次序,須要移動多少次?
提示:這是一個難題,實在應該是個「附加題」。blog

本文章針對b問題
總共有2n個圓盤在A柱上,咱們如今須要把它們所有挪到C柱上
b問題的限制條件是:最後保持原來的上下次序不改變
因此隱藏含義就是:移動的過程當中,同一大小型號的盤子的上下次序無所謂遞歸

對於這類遞歸的題目,咱們應該先找規律,而後再推出遞歸式,寫出代碼數學

PS:這邊咱們要寫的程序是,輸出每個步驟,例如將幾號盤從幾號柱子移動到幾號柱子it

思路推動

n = 1 時,執行如下算法:io

  1. 第 n(上) 圓盤從 A 移到 C,需 1 步;
  2. 第 n(下) 圓盤從 A 移到 B,需 1 步;
  3. 第 n(上) 圓盤從 C 移到 B,需 1 步。




咱們將圓盤從上到下依次按照1~2n進行編號
咱們中間的輸出步驟過程暫時不考慮2k-1和2k的差異
先簡化難度,將2k-1和2k當作同樣的class

(可是最後上下順序仍是原來的,最後總步數不影響,只是簡化中間輸出過程)

輸出中間步驟時統一輸出"k號型盤子"
第三篇文章中會講到區別2k-1與2k的作法

由於順序要和初始的同樣
第2n號圓盤應該,被放在第C柱的最低端
而後再放上2n-1號盤子
最後再將1~(2n-2)號盤子所有移到C柱上
可是咱們怎麼肯定,移動1~(2n-2)號盤子就是順序的呢?
由於執行一次\(A_{n-1}\)操做後,只有最下面兩個盤子的順序會互換
由於\(A_n\)中須要執行兩次\(A_{n-1}\)操做
因此執行兩次以後就回到了原來的順序
具體證實會在第三篇中講到

1.第 1~n-1 圓盤從 A 移到 B,需 \(A_{n-1}\) 步;
2.第 n(上) 圓盤從 A 移到 C,需 1 步;
3.第 1~n-1 圓盤從 B 移到 C,需 \(A_{n-1}\) 步;
4.第 n(下) 圓盤從 A 移到 B,需 1 步;
5.第 1~n-1 圓盤從 C 移到 A,需 \(A_{n-1}\) 步;
6.第 n(上) 圓盤從 C 移到 B,需 1 步;
7.第 1~n-1 圓盤從 A 移到 B,需 \(A_{n-1}\) 步。





代碼實現

#include<cstdio>
#include<algorithm>
#include<stack>
#include<vector>
using namespace std;
int step;
void Move(int id,char from,char to) {
	printf("第%d步:將%d號型盤子%c-->%c\n",++step,id,from,to);
	return ;
}
void AHanio(int n,char spos,char tpos,char epos) {
	if(n==1) {
		Move(n,spos,epos);
		Move(n,spos,epos);
	} else {
		AHanio(n-1,spos,epos,tpos);
		Move(n,spos,epos);
		Move(n,spos,epos);
		AHanio(n-1,tpos,spos,epos);
	}
}
void BHanio(int n,char spos,char tpos,char epos) {
	if(n==1) {
		Move(n,spos,tpos);
		Move(n,spos,epos);
		Move(n,tpos,epos);
	} else {
		AHanio(n-1,spos,tpos,epos);
		Move(n,spos,tpos);
		AHanio(n-1,epos,spos,tpos);
		Move(n,spos,epos);
		AHanio(n-1,tpos,epos,spos);
		Move(n,tpos,epos);
		AHanio(n-1,spos,tpos,epos);
	}
}
int main() {
	int n;
	scanf("%d",&n);
	BHanio(n,'A','C','B');
	printf("最後總的步數爲%d步\n",step);
}
/*
8 3
16 11
32 27
64 59
*/

封閉式推導

根據遞歸式,咱們能夠得出

咱們設最終完成2n個圓盤的移動所須要的總步數爲\(B_n\)
第一篇文章中,已知問題a對應的\(A_n=2^{n+1}-2\)

\(\begin{align} &B_n=A_{n-1}+1+A_{n-1}+1+A_{n-1}+1+A_{n-1}\\ &=4\times A_{n-1}+3\\ &=4\times (2^{n}-2)+3\\ &=2^{n+2}+5\\ \end{align}\)

相關文章
相關標籤/搜索