漢諾塔:漢諾塔(又稱河內塔)問題是源於印度一個古老傳說的益智玩具。大梵天創造世界的時候做了三根金剛石柱子,在一根柱子上從下往上按照大小順序摞著64片黃金圓盤。大梵天命令婆羅門把圓盤從下面開始按大小順序重新擺放在另一根柱子上。並且規定,在小圓盤上不能放大圓盤,在三根柱子之間一次只能移動一個圓盤。
二、漢諾塔移動過程漢諾塔動畫: 演示圓盤移動過程(此動圖來源於網絡)
下面分三種情況分別演示每個盤子的移動過程(n 代表圓盤數量):
1個圓盤的情況:
2個圓盤的情況:
3個圓盤的情況:
三、漢諾塔算法思想當 n 等於 1 的時候,直接把圓盤從 A 移動到 C;
當 n > 1 的時候:
把 A 柱子上面的 (n-1) 個盤子,從 A 移動到 B;
把 A 柱子上面的第 n 個盤子由 A 移動到 C;
把第一步 B 柱子上的 (n-1) 個盤子由 B 移動到 C
在算法的實現過程中,我們利用遞歸的思想。來模擬移動過程以及總共移動的次數。
1.示例代碼public class Hanoi {
/**
* 移動的次數
*/
static int m = 0;
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.print("玩漢諾塔,請輸入圓盤的個數:");
int n = input.nextInt();
char a = 'A';
char b = 'B';
char c = 'C';
hanoi(n, a, b, c);
System.out.println("把A上的圓盤都移動到了C上,總共移動了" + m + "次。");
}
/**
* 漢諾塔
*
* @param n 盤子的數量
* @param a 柱子 A
* @param b 柱子 B
* @param c 柱子 C
*/
public static void hanoi(int n, char a, char b, char c) {
if (n == 1) {
move(1, a, c);
} else {
// 遞歸 把A柱子上面的n-1層,從A,經C,到B
hanoi(n - 1, a, c, b);
move(n, a, c);
// 遞歸 把B柱子上的n-1層,從B,經A,到C
hanoi(n - 1, b, a, c);
}
}
/**
* 移動
*
* @param n 圓盤的個數
* @param i 移動前的位置
* @param j 移動後的位置
*/
public static void move(int n, char i, char j) {
m++;
System.out.println("第" + m + "次: " + n + "號圓盤: " + i + " -> " + j);
}
}代碼執行結果:
玩漢諾塔,請輸入圓盤的個數:3
第1次: 1號圓盤: A -> C
第2次: 2號圓盤: A -> B
第3次: 1號圓盤: C -> B
第4次: 3號圓盤: A -> C
第5次: 1號圓盤: B -> A
第6次: 2號圓盤: B -> C
第7次: 1號圓盤: A -> C
把A上的圓盤都移動到了C上,總共移動了7次。
2.延伸問題如果移動一個圓盤需要1秒鐘的話,等到64個圓盤全部重新落在一起,需要多少長時間?
1個圓盤的時候,2的1次方減12個圓盤的時候,2的2次方減13個圓盤的時候,2的3次方減14個圓盤的時候,2的4次方減1........n個圓盤的時候,2的n次方減1
當 n=64的時候是(2的64次方減1)次。
代碼示例:
public class Test {
public static void main(String[] args) {
double a = Math.pow(2, 64) - 1;
System.out.println("2^64-1的值: " + a);
// 移動一個圓盤需要1秒,一年可以移動b個圓盤
double b = 60 * 60 * 24 * 365;
System.out.println("一年時間移動圓盤的個數: " + b);
// 移動64個圓盤需要的時間
double time = a / b;
System.out.println("移動64個圓盤需要的時間: " + time + " 年");
}
}代碼執行結果:
2^64-1的值: 1.8446744073709552E19
一年時間移動圓盤的個數: 3.1536E7
移動64個圓盤需要的時間: 5.84942417355072E11 年移動完所有的圓盤大概需要5849億年,這是一個多麼可怕的數字!