Hanoi塔問題是源於印度一個古老傳說的益智玩具。設a,b,c是三個塔座,開始時,在塔座a上有一疊共n個圓盤,這些圓盤自上而下,由大到小疊在一塊兒,各圓盤的編號爲1,2,3,...,n。現要求將塔座a上的這一疊圓盤移動到塔座b上,並仍按從到到小的順序疊置。再移動圓盤時應該遵照如下移動規則:數組
規則一:每次只能移動一個圓盤。函數
規則二:不容許將較大的圓盤壓在較小的圓盤上面。spa
規則三:在知足規則1、規則二的狀況下,可將圓盤移動到啊a,b,c中任一塔座上。code
如圖爲一Hanoi塔問題的移動步驟:blog
a遞歸
圓盤總數爲n,當n=1時,只要將編號爲1的圓盤從塔座a直接移動到塔座b。當n>1時,須要利用塔座c做爲輔助,將n-1個較小的圓盤依照移動規則從塔座a移動至塔座c,而後將最大的圓盤從塔座a移動至塔座b,再將n-1個圓盤從塔座c移動至塔座b,T(n)=2^(n-1)-1。因爲n-1個圓盤以一樣的方式移動了兩次,能夠利用遞歸方法來解決。這個就是典型的Hanoi塔遞歸問題。get
public static void hanoi(int n,int a,int b,int c){ if(n>0){ hanoi(n-1,a,c,b); move(a,b); hanoi(n-1,c,b,a); } }
若是將三個塔座a,b,c改成四個塔座a,b,c,d,利用分治法則和概括法分紅兩個小規模問題。class
T(n)來表示最小步數,能夠知道T(1)=1,T(2)=3,當n>=3時,假設已經輸出T(1),T(2),…,T(n-1),則T(n)能夠這樣計算:循環
for i=1;i<n;i++方法
一:先從塔座a移動i個圓盤到塔座d(b,c),塔座b,c做爲輔助,移動步數爲T(i)。
二:剩下的n-i個圓盤只能夠在三個塔座之間移動,利用Hanoi函數將其由塔座a移動至塔座,塔座c做爲輔助,移動步數爲T(n-i)=2^(n-i)-1。
三:再將塔座d中的i個圓盤移動至塔座b,塔座c,a做爲輔助(與步一移動方式相同)移動步數爲T(i)。
public class Han { //建立一個靜態數組用於存儲移動的圓盤的最小步數 static int[] a=new int [65]; //建立一個靜態數組用於存儲先移動的圓盤的個數 static int[] s=new int [65]; public static void step() { a[0] = 0; a[1] = 1; a[2] = 3; //先移動圓盤個數的循環 for (int n = 3; n <= 64; n++) { double min = 200000; double temp = 0; int temp2 = 0; //一個一個移動計算步數和圓盤個數 for (int i = 1; i < n; i++) { temp = 2 * a[i] + Math.pow(2, n - i) - 1; if (temp < min) { min = temp;//計算出移動總步數並賦值 temp2 = i;//計算出先移動圓盤數並賦值 } a[n] = (int) temp; s[n] = temp2; } } }
public static void hanoi4(int n,int a,int b,int c,int d,int []s){ if(n>=3){ hanoi4(s[n],a,b,c,d,s); hanoi(n-s[n],a,c,b); hanoi4(s[n],d,a,b,c,s); }else{ if(n==1){ move(a,b); } if(n==2){ hanoi(2,a,c,b); } } }
示例:
在Hanoi塔問題中若是塔的個數變爲a,b,c,d四個,現要將n個圓盤從a所有移動到d,移動規則不變,編寫移動步數最小的方案和具體的移動過程(只考慮n<=64),並演示當n=9時的情形。
package jihe; /** * author Gsan */ public class Han { //建立一個靜態數組用於存儲移動的圓盤的最小步數 static int[] a=new int [65]; //建立一個靜態數組用於存儲先移動的圓盤的個數 static int[] s=new int [65]; public static void step() { a[0] = 0; a[1] = 1; a[2] = 3; //先移動圓盤個數的循環 for (int n = 3; n <= 64; n++) { double min = 200000; double temp = 0; int temp2 = 0; //一個一個移動計算步數和圓盤個數 for (int i = 1; i < n; i++) { temp = 2 * a[i] + Math.pow(2, n - i) - 1; if (temp < min) { min = temp;//計算出移動總步數並賦值 temp2 = i;//計算出先移動圓盤數並賦值 } a[n] = (int) temp; s[n] = temp2; } } } public static void hanoi(int n,int a,int b,int c){ if(n>0){ hanoi(n-1,a,c,b); move(a,b); hanoi(n-1,c,b,a); } } public static void move(int a,int b){ System.out.println("move"+a+"to"+b); } public static void hanoi4(int n,int a,int b,int c,int d,int []s){ if(n>=3){ hanoi4(s[n],a,b,c,d,s); hanoi(n-s[n],a,c,b); hanoi4(s[n],d,a,b,c,s); }else{ if(n==1){ move(a,b); } if(n==2){ hanoi(2,a,c,b); } } } public static void main(String[] args) { int n=9; step(); hanoi4(n,1,2,3,4,s); System.out.println("9個圓盤移動的最小步數爲:"+a[n]); } }
運行結果: