漢諾塔問題(+遞推公式)
阿新 • • 發佈:2018-12-24
漢諾塔問題是使用遞迴解決問題的經典範例。
漢諾(Hanoi)塔問題:古代有一個梵塔,塔內有三個座A、B、C,A座上有64個盤子,盤子大小不等,大的在下,小的在上(如圖)。有一個和尚想把這64個盤子從A座移到B座,但每次只能允許移動一個盤子,並且在移動過程中,3個座上的盤子始終保持大盤在下,小盤在上。在移動過程中可以利用B座,要求列印移動的步驟。如果只有一個盤子,則不需要利用B座,直接將盤子從A移動到C。
- 如果有2個盤子,可以先將盤子1上的盤子2移動到B;將盤子1移動到c;將盤子2移動到c。這說明了:可以藉助B將2個盤子從A移動到C,當然,也可以藉助C將2個盤子從A移動到B。
- 如果有3個盤子,那麼根據2個盤子的結論,可以藉助c將盤子1上的兩個盤子從A移動到B;將盤子1從A移動到C,A變成空座;藉助A座,將B上的兩個盤子移動到C。這說明:可以藉助一個空座,將3個盤子從一個座移動到另一個。
- 如果有4個盤子,那麼首先借助空座C,將盤子1上的三個盤子從A移動到B;將盤子1移動到C,A變成空座;藉助空座A,將B座上的三個盤子移動到C。
- 程式碼如下:
拓展:遞推公式:f(n)=f(n-1)*2+1;#include<stdio.h> #include<string.h> #include<stdlib.h> #include<limits.h> #include<algorithm> #include<queue> #include<stack> #include<vector> #include<math.h> #define maxn 1000005 int step; void move(int a,int b) { printf("move from %d to %d \n",a,b); } void hanoi(int n,int a,int b,int c)//a表示起點,b表示過渡的柱子,c表示終點 { if(n==1) { ++step; move(a,c); } else { ++step; move(a,c); hanoi(n-1,a,c,b); hanoi(n-1,b,a,c); } } int main() { int T,i,j,n; scanf("%d",&T); while(T--) { step=0; scanf("%d",&n); hanoi(n,1,2,3); printf("Total steps is %d\n",step); } }
- 拓展題目如下:
-
漢諾塔(二)
時間限制:3000ms | 記憶體限制:65535KB 難度:5- 描述
-
漢諾塔的規則這裡就不再多說了,詳見題目:漢諾塔(一)
現在假設規定要把所有的金片移動到第三個針上,給你任意一種處於合法狀態的漢諾塔,你能計算出從當前狀態移動到目標狀態所需要的最少步數嗎?
- 輸入
- 第一行輸入一個整數N,表示測試資料的組數(0<N<20)
每組測試資料的第一行是一個整數m表示漢諾塔的層數(0<m<32),隨後的一行有m個整數Ai,表示第i小的金片所在的針的編號。(三根針的編號分別為1,2,3) - 輸出
- 輸出從當前狀態所所有的金片都移動到編號為3的針上所需要的最少總數
- 樣例輸入
-
2 3 1 1 1 3 1 1 3
- 樣例輸出
-
7 3
- 程式碼如下:
#include<stdio.h> #include<string.h> int step[33],num[33]; void find() { step[0]=1; for(int i=1;i<=33;i++) step[i]=step[i-1]*2; } int main() { find(); int t,n,m; scanf("%d",&t); while(t--) { int t=3,i,sum=0; scanf("%d",&n); for(i=0;i<n;i++) scanf("%d",&num[i]); for(i=n-1;i>=0;i--) { if(num[i]!=t) { sum+=step[i]; t=6-num[i]-t;//當n-1時,如果第n-1小的(也就是最大的)不在3號針上,比如在2上,則會把小於第n-1個盤的其他盤移到1號針上去 //然後判斷第n-2小的盤在不在1號針上,依次類推......也就是針的總和數6減去num[i]所在的號數,減去n-1個盤所在的位置(自己模擬畫畫圖) } } printf("%d\n",sum); } }