它的解法可以採用分解法,把一個大的問題,逐步分解成一個個小問題。比如我們想把A中的盤子挪到B上,可以把問題分解成,將A的前n-1個盤子先挪到C,然後把A中最後一個挪到B,再把C的n-1個盤子挪到B;然後n-1個盤子的問題可以分解成,先將C中前n-2個盤子放到A,把C的最後一個盤子放到B,再把A中n-2個盤子放到B上。。。。。。這樣逐步遞歸,從而實現整個算法。
這裏面還要說一下遞歸問題:編寫 遞歸函數時,必須告訴它何時停止遞歸。正因爲如此,每個遞歸函數都有兩個部分:基線條件(base case)和遞歸條件(recursive case)。遞歸條件是指函數調用自己,而基線條件則是指函數不再調用自己,從而避免形成無線循環。
D&C(divide and conquer)分而治之—— 一種遞歸式問題解決方案。(1)找出基線條件,這種條件必須儘可能簡單。
(2)不斷將問題分解(縮小規模),知道符合基線條件。
漢諾塔問題是NP完全問題,也就是說,它的算法時間複雜度是指數級的,分析如下,假設我們要挪動n個鐵餅,把時間標記爲T(n), 我們先挪動n-1個鐵餅,所需時間就是T(n-1), 然後再挪動一個鐵餅,時間爲O(1), 然後再挪動n-1個鐵餅,時間爲T(n-1), 於是我們有: T(n) = 2*T(n-1) + O(1).
這個公式把T(n)解出來結果爲: T(n) = 2^n;
這就意味着,每增加一個鐵餅,所需的挪動步驟幾乎是原來的兩倍
下面來看程序:
在HanoiTower類中聲明三個變量,n表示有多少個盤子,from,to表示從from移動到to杆上。
首先判斷一下邊界條件(這是一個良好的編程習慣),之後調用buildHanoi方法實現遞歸。
在buildHanoi方法中,我們要先找到基線條件:就是到參數top和bottom相同的時候,也就是說指向塔尖的指針和指向塔底的指針重合,那就意味着只有一個盤子,說明遞歸到頭可以跳出了。而遞歸條件就如上面所講的
buildHanoi(from, other, top, bottom-1);將n-1個鐵餅移動到臨時杆上,再把最後一個鐵餅移動到目標杆上。
buildHanoi(other, to, top, bottom-1);最後將臨時杆上的鐵餅移動到目標杆上。
package p_11_hanoi;
import java.util.Scanner;
import java.util.Stack;
public class HanoiTower {
private int from = 0;
private int to = 0;
private int n = 0;
Stack<String> stack = new Stack<String>();
public HanoiTower(int n, int from, int to) throws Exception{
if(n<=0 || from>n || from<0 || to>n || to<0){
throw new Exception("this is a invalid parameter!");
}
this.n = n;
this.from = from;
this.to = to;
buildHanoi(this.from, this.to, 1, n);
}
public void buildHanoi(int from, int to, int top, int bottom){
String s = "Moving " + bottom + " from " + from + " to " + to;
if(top == bottom){
stack.push(s);
return; // add!!!
}
int other = from;
//for(int i=0; i<n; i++){
for(int i=1; i<=n; i++) {
if(i != from && i != to){
other = i;
break;
}
}
buildHanoi(from, other, top, bottom-1);
stack.push(s);
buildHanoi(other, to, top, bottom-1);
}
public void printStack(){
if(stack.size() == 1){
System.out.println(stack.pop());
return;
}
String tmp = stack.pop();
printStack();
System.out.println(tmp);
}
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int from = in.nextInt();
int to = in.nextInt();
try{
HanoiTower ht = new HanoiTower(n, from, to);
ht.printStack();
}catch(Exception e){
e.printStackTrace();
}
}
}