小知識系列(3):Hanoi塔(漢諾塔,河內塔)

Sky王某人發表於2020-11-21

同樣,藉此來強化學習,但是說實話我寫這個感覺很玄。Hanoi塔是昨天剛學到的東西,想了很久,感覺還是沒有悟透,可能學到更多新東西,或產生了新的想法,或突然悟到了什麼,屆時會再做修改。
看了很多關於Hanoi塔的部落格,說實話都是一頭霧水,可能也是因為鄙人的理解能力有欠缺。一直看到一位博主的一篇講解才略有啟發,部落格↓↓↓
傳送門

(後續)
發現一位B站UP主的講解更加細緻,留下連結:↓↓↓
傳送門

OK,言歸正傳。
Hanoi塔起源是什麼?我們不多說,有興趣的可以查一下。

Hanoi塔的規則是什麼?

有三根柱子,將A柱子上所有的圓盤轉移到C柱子。
1.在小圓盤上不能放大圓盤。
2.在三根柱子之間一回只能移動一個圓盤。
3.只能移動在最頂端的圓盤。

具體操作?

我們從最簡單的開始:
一個盤:A→C;
兩個盤:A→B,A→C,B→C;
三個盤:A->C , A->B , C->B , A->C , B->A , B->C , A->C

一個盤的時候,直接由A柱到C柱
兩個盤的時候,把不是最大的一個放到B柱,然後把最大的從A放到C柱,再把B柱上的小盤放到C柱
三個盤的時候,步驟相同其實,就是把不是最大的放到B柱然後把最大的放到C柱,再借助A柱重複做一次兩個盤的情況的步驟(其實就是重複兩次)。

我們要解決n層Hanoi塔就要解決n-1層Hanoi塔,
我們要解決n-1層Hanoi塔就要解決n-2層Hanoi塔,
……
……
我們要解決3層Hanoi塔就要解決2層Hanoi塔,
我們要解決2層Hanoi塔就要解決1層Hanoi塔,
(分治思想)

總結一下:
只需要兩步來解決這個問題:
第一步:
把n-1個小盤,從A柱移動到B柱,
把第n個小盤,由A柱移動到C柱。
第二步:
把n-1個小盤,從B柱移動到C柱。←其實這一步就是換位置後重復第一步。

接下來做題有疑問 可以返回這裡檢視。

在這裡我先放上一道題以及完整的程式碼:

Description:

如圖所示的三根針,其中A針上穿好了由大到小的64片金片,不論白天黑夜,總有一個和尚在按照下面的法則移動金片:一次只移動一片,不管在哪根針上,小片必須在大片上面。和尚們預言,當所有的金片都從A針移到C針上時,世界就將在一聲霹靂中消失,這就是所謂的漢諾塔。請程式設計求出將A針上所有金片移到C上的步驟。
在這裡插入圖片描述

Input

標準輸入,一個整數N,表示有N個金片。

Output

標準輸出,輸出所有步驟,每一步驟佔一行。

Input Copy
3
Output
A->C
A->B
C->B
A->C
B->A
B->C
A->C

完整程式碼:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
void f(int n,char a,char b,char c)
{
	if(n==1)
		cout<<a<<"->"<<c<<endl;
	else
	{
		f(n-1,a,c,b);
		cout<<a<<"->"<<c<<endl;
		f(n-1,b,a,c);
	}
}
int main()
{
	int n;
	cin>>n;
	f(n,'A','B','C'); 
	return 0;
}

我們要理解一個問題f()函式的4個位置分別的什麼意思?
例如f(n,‘A’,‘B’,‘C’)
這裡我們不是按照順序分析:
第二個位置,就是起始位置位置1),也就是,你要把小盤從哪個柱子上拿走。
第四個位置,就是目標位置位置3),也就是,你要把小盤全都按照順序放到這跟柱子上。
第三個位置,就是中轉位置位置2),也就是,你要把最大的盤子,暢通無阻的從起始位置放到目標位置,其他的n-1個盤子必須放在這根柱子上。
第一個位置,就是我要轉移小盤的數量。

可能發現了,我又寫出位置1,位置2,位置3,為什麼呢?
這是為了不讓我們搞混與ABC搞混,ABC只是柱子的編號。
我們逐步分析,首先看main函式:

int main()
{
	int n;
	cin>>n;
	f(n,'A','B','C'); 
	return 0;
}

什麼意思?根據之前說過的,我們可以知道,**就是把n個小盤,由A柱經B柱中轉放到C柱上。**這也就是我們的目標。

再來看函式部分

void f(int n,char a,char b,char c)
{
	if(n==1)
		cout<<a<<"->"<<c<<endl;
	else
	{
		f(n-1,a,c,b);
		cout<<a<<"->"<<c<<endl;
		f(n-1,b,a,c);
	}
}

當只有一個盤子的時候,只要把A的盤子放到B即可。
如果大於1個,那麼f(n-1,a,c,b)先把n-1個小盤,由A經過C的中轉放到B。
然後再把第n個由A放到B
然後再把剩下的n-1個小盤由B經過A的中轉放到C
(步驟最開始有提到過)

TIP

1.理解過程,分治的思想,把一個大問題分成若干個小問題,如果你試圖自己置身於一個遞迴,我想不是天賦異稟,的確不一定能看的透……
在這裡插入圖片描述
所以你只要告訴他什麼情況該做什麼就好了,有些東西是一般人做不來的……比如鄙人……。

以上只是鄙人的拙見,如有不足之處,敬請斧正,如有難以理解的地方,亦可以指出。

相關文章