1. 程式人生 > 其它 >漢諾塔問題,對遞迴的進一步思考

漢諾塔問題,對遞迴的進一步思考

傳送門

題目意思並不難理解,有三根柱子 a , b , c。 a 柱子上有一堆從小到大排列的圓盤,把圓盤從下面開始按大小順序重新擺放在 c 柱子上。並且規定,任何時候,

小圓盤上都不能放大圓盤,且在三根柱子之間一次只能移動一個圓盤。問應該如何操作?

初次接觸類似的問題,乍看之下肯定會感覺無從下手。

假設有64個圓盤,要把64個圓盤從a柱子移動到c柱子上,第一步應該怎麼做?雖然可以肯定,第一步唯一的選擇是移動a最上面的那個圓盤,但是應該將其移到b還是c呢?很難確定。因為接下來的第二步、第三步……直到最後一步,看起來都是很難確定的。能立即確定的是最後一步:最後一步的盤子肯定也是a最上面那個圓盤,並且是由a或b移動到c——此前已經將63個圓盤移動到了c上。也許你會說,管他呢,先隨便試著移動一下好了。如果你這麼做,你會發現,接下來你會面臨越來越多類似的選擇,對每一個選擇都“試”一下的話,你會偏離正確的道路越來越遠,直到你發現你接下來無法進行為止。

一股腦地考慮每一步如何移動很困難,我們可以換個思路。先假設除最下面的盤子之外,我們已經成功地將上面的63個盤子移到了b柱,此時只要將最下面的盤子由a移動到c即可。

當最大的盤子由a移到c後,b上是餘下的63個盤子,a為空。因此現在的目標就變成了將這63個盤子由b移到c。這個問題和原來的問題完全一樣,只是由a柱換為了b柱,規模由64變為了63。因此可以採用相同的方法,先將上面的62個盤子由b移到a,再將最下面的盤子移到c……對照下面的過程,試著是否能找到規律:

  1. 將b柱子作為輔助,把a上的63個圓盤移動到b上
  2. 將a上最後一個圓盤移動到c
  3. 將a作為輔助,把b上的62個圓盤移動到a上
  4. 將b上的最後一個圓盤移動到c
  5. ......

 

也許你已經發現規律了,即每次都是先將其他圓盤移動到輔助柱子上,並將最底下的圓盤移到c柱子上,然後再把原先的柱子作為輔助柱子,並重復此過程。
這個過程就是遞迴,即定義一組基本操作,這組操作將規模小一點(或大一點)的操作當做一個整體——無需關心它的細節,只當它已經完成了——然後執行剩下的操作。而在更小或更大的規模中也依此操作,直到規模達到預定值。

程式碼

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1;

void solve(int n, char
a, char b, char c) { if (n == 1) { printf("No.%d disk: %c->%c\n", n, a, c); } else { solve(n - 1, a, c, b);// a移到b,c為輔助柱 printf("No.%d disk: %c->%c\n", n, a, c); solve(n - 1, b, a, c); // b移到c,a為輔助柱 } } int main() { int n; cin >> n; solve(n, 'a', 'b', 'c'); return 0; }