漢羅塔問題java數學模型(從數學原型到數學模型)

雙花誕發表於2017-10-28

漢羅塔問題想必大家都知道了,然而今天我才第一次做,問題分類也很簡單,遞迴,遞迴是很常用的演算法,就是研究n項和n-1項的關係,下面算是自己以一個沒有經驗的人第一次做的思路。(又是學習記錄做成教程系列)

那先從簡單的開始吧,首先我只用大腦只能推出前3組的移動過程,然後到4個盤子的時候基本就沒有思路了,並不敢肯定之間的聯絡,過程一下想不出來,那就想結果吧。前幾個都能推出來f(1)=1;f(2)=3;f(3)=7;然後就可以分析規律了。

開始分析一個盤子時,A直接移過去C;

兩個盤子時,把A上面的小的放在B上,然後A下面的移到C,再然後B上面的移動到C; 然後是 三個盤子時,很明顯也要進行過渡,這裡過程不寫了,下面有。所以這個時候就可以看出來了,2個盤子時,就是把A上面的放在B上,把A下面的放在C上,這個時候就變成了一個盤子的情況(只是AB的位置交換了);

然後是三個盤子的時候,也是先把A除了最下面的盤子放在B上(最小的兩個),然後把最大的一個盤子放在C上,然後又變成了兩個盤子的情況了。

所以有n個盤子的推測也出來了,先把n-1個盤子整體放在B上,然後把A最下面的盤子放在C上,所以移動總次數=n-1移動的次數+移動成該情況的次數+1(把最大的盤放在C)

f(n-1)這個就是簡單的次數,那要移動成上面的步驟需要的次數理解也很簡單眼中只留下n-1個盤子,忽略最大的那一個,把目的C換成目的B,那還是=f(n-1)

所以f(n)=2*f(n-1)+1,那麼只用迭代就可以算出來了,也就是下面的第一個方法,但如果要移動過程就適合使用遞迴了,但遞迴的理解最好還是基於這個公式來做,為了便於理解找出規律貼上了,前4個盤子的情況。

這裡檢驗一下上面的公式,這裡分別是2,3,4個盤子的移動步驟,有下面三個規律(上面提過的就沒寫了):

  1.都是在f(n-1)的步驟將A的盤子(最大的那個)移動到C。

2.f(n)的前f(n-1)項和f(n-1)的對應項B和C是相反的,其他都是一模一樣的。

3.f(n)的後f(n-1)項和f(n-1)的對應項A和B是相反的,其他都是一模一樣的。

總結:前f(n-1)步的過渡盤是C,後f(n-1)步過渡盤是B。中間插了一步A到C。


那這樣我們就知道移動的規律了,然後程式設計就很簡單了(其實也沒那麼簡單)

package test1;

public class Hanluota {
	int count = 0;
	
	public void index(int n) {
		int result = 0;
		for (int i = 0; i < n; i++) {
			result = result*2 +1;
		}	
		System.out.println("實際移動次數"+result);
	}
	
	//n為需要移動的盤子個數,a是起始位置,c是目的盤,b是過渡盤
	public void process(int n,char a,char b,char c) {
		if (n==1) {
			count++;
			System.out.println("第"+count+"步從" + a + " 移動盤子" + n + " 號到" + c);
			return;
		}	
		process(n-1, a, c, b); 		//過渡盤逐次交換,比如2,A,B,C是輸入時,到這裡是1,A,C,B,而n=2時第一步就是A-B,可以參考上面
		count++;
		System.out.println("第"+count+"步從" + a + " 移動盤子" + n + " 號到" + c);
		process(n-1, b, a, c);		//上面的n-1最後結束是1,return返回的n是上一個數2
	}	  
	  
	    public static void main(String[] args) { 
	    	Hanluota a1 = new Hanluota();
	        a1.process(4, 'A', 'B', 'C');   
	        a1.index(4);
	    }  
	}  
這個結果就不貼了,上面 有,但其實這個遞迴程式碼是屬於一個常見的遞迴模型,不然是很難理解的,下面寫了個型別一樣的模型,這個模型的特點完全符合剛剛上面提到的三個規律,不然別的方法還真是想不到,試了次迭代,沒成功。。。

package test;

public class digui {
	
	public void name(int n) {
		if (n==2) {
			return;
		}
		name(n-1);
		System.out.print(n-1+"\t");
		name(n-1);
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		digui a1 = new digui();
		a1.name(6);
	}
}
貼一下結果232423252324232

當n=5時是 232232

這個應該看出來了吧,遞迴不斷呼叫自身是無限迴圈的,這樣需要一個停止判斷,就是if語句,但不是每個name(2)都可以結束整個迴圈的。

而是方法中的最後一個name(2)才結束方法,當方法中兩個name(n-1)都完成時就會返回上一個值,理解這個模型的重點是知道方法中的每個方法都要到n=2時才結束迴圈,具體過程不debug是很難理解的,懂了原理i就好理解上面的具體的程式碼了,唯一要改的就是移動的對於順序,寫下來比較好懂一下(確定已經完全是做成了教學系列,不過自己也算學習了)







相關文章