本文是該系列文章中的第一篇。將對中國傳統的智力玩具九連環作簡要的介紹。並從數學的角度對其建模。所謂建模就是在定義的基礎之上羅列一系列的可證實的定理和推論,從而爲該問題的解決創建堅實的理論基礎。全部這些都將在本系列的後續文章中做爲編程實現的指導和基礎。算法
記得在完成學業,開始工做後不久,偶爾在路邊攤上看到九連環,喜歡並買了回來。很快發現其背後是一個純粹乾淨的遞歸,因而能夠熟練的解開並安裝還原。彼時也未曾寫成電腦程序。要寫的話也多半是使用C/C++/Java/Python這類命令式編程語言,簡潔明瞭,沒有多少難度,也沒有什麼激動人心之處。後來東西丟了,也就多年沒再玩過。前段時間十一歲的兒子在網上爲本身淘來一個,竟然也能熟練地拆裝,這多少令我有些驚訝。因而想着是否能夠乘此機會教教他電腦編程。不成想思考的時候頭腦裏出現的都是這幾年努力學習的Haskell,發現Haskell跟數學是如此的接近,也一如數學通常優美。奈何小傢伙不願學習這個,隨他去吧,也許緣分未到呢。好歹把想明白的東西記錄成文,萬一未來有機會,有緣分,至少不須要從頭作起。編程
九連環的綜合信息能夠參見維基百科中的條目。一些圖片以下,依次是完整未解的,解到一半的和徹底解開爲兩部分的九連環:segmentfault
能夠看到:編程語言
ON n
或是OFF n
。多個步驟的有序排列稱爲一個步驟序列。基本的操做經過實物演示比較容易理解,若是讀者有一個九連環在手,就能夠很容易地驗證這些操做。學習
ON 1
,拆下的動做爲 OFF 1
。[OFF 2, OFF 1]
。[ON 1, ON 2]
。ON n
或者 OFF n
。takeOff(n)
或是putOn(n)
的解。定理1:takeOff(1)
的解法步驟序列爲[OFF 1]
,putOn(1)
的解法步驟序列爲[ON 1]
。
根據基本操做1,定理1顯而易見spa
定理2:takeOff(2)
的解法步驟序列爲[OFF 2, OFF 1]
,putOn(2)
的解法步驟序列爲[ON 1, ON 2]
。
根據基本操做2和3,定理2顯而易見。code
定理3:當n>2
時,takeOff(n)
的解法依次由如下幾個部分組成:1) takeOff(n-2)
2) OFF n
3) putOn(n-2)
4) takeOff(n-1)
;而putOn(n)
依次由如下幾個部分組成 1) putOn(n-1)
2) takeOff(n-2)
3) ON n
4) putOn(n-2)
。
定理3能夠經過數學概括法證實,其中的起始步驟爲定理1和定理2,遞推步驟爲基本操做4blog
推論1:takeOff(n)
的解法步驟序列和putOn(n)
的解法步驟序列互爲逆反序列,步驟序列A的逆反序列能夠經過如下步驟獲得: 1) 將序列A反序獲得序列A' 2) 對A'中的每一個步驟取其反動做,反動做的定義爲ON n
和OFF n
互爲反動做。能夠看出若是B是A的逆反序列,那麼在B的基礎上取逆反序列,其結果就等於A。
推論1一樣能夠用數學概括法證實,當n<=2
時,經過定理1和定理2顯而易見。當n>2
時,經過定理3提供的步驟能夠遞推獲得。遞歸
推論2:takeOff(n)
的解法步驟序列和putOn(n)
的解法步驟序列含有的步驟數目相等。
根據推論1和步驟序列的逆反序列定義和算法,推論2顯而易見。圖片
推論3:對於任何整數m, n
,若是m>n
,那麼第m
環的狀態(裝上或是卸下)不影響takeOff(n)
或者putOn(n)
的解,同時解決takeOff(n)
或者putOn(n)
問題也不會改變第m環的狀態。
這條推論仍然能夠用數學概括法證實,當n<=2
時,經過定理1和定理2顯而易見。當n>2
時,定理3提供的步驟不受第m環的影響而且不會操做第m環。
至此咱們已經擁有建立一個遞歸模型所須要的所有理論基礎。定理1和定理2肯定了遞歸結束的基本條件;定理3描述了怎樣把一個較大的問題拆分紅幾個較小的問題,從而一步步拆分直至到達遞歸結束的基本條件;推論3事實上明確了咱們能夠在整個過程當中放心地把任何一個較大的問題拆分紅多個較小的問題;而推論1和推論2使得咱們在某些狀況下能使用等價的替代算法,從而簡化編寫的實現代碼。
下圖顯示了takeOff(5)
怎樣一步步被拆分紅更小的問題,最終達到基本條件的過程。
能夠看到該求解過程造成了一棵樹,在樹中將全部葉結點所包含的動做依次鏈接成一個序列,就是根節點所表明的問題takeOff(5)
的解法步驟序列。能夠看到這個序列是[OFF 1, OFF 3, ON 1, OFF 2, OFF 1, OFF 5, ON 2, ON 1, OFF 1, ON 3, ON 1, OFF 2, OFF 1, OFF 4, ON 2, ON 1, OFF 1, OFF 3, ON 1, OFF 2, OFF 1]
,一共21個步驟。
觀察解法樹的最左側分支直到末端的葉結點,咱們看到經過不斷的拆分takeOff(n)
到takeOff(n-2)
再到takeOff(n-4)
最終到達基本條件takeOff(1)
或是takeOff(2)
,特別地,當n爲奇數的時候將最終拆分到takeOff(1)
,爲偶數時將最終拆分到takeOff(2)
。這樣就獲得一個有趣的推論:拆解n連環時,若是n爲奇數,則第一步是OFF 1
,爲偶數時第一步爲OFF 2
。該推論對於自頂向下地編程實現沒有什麼特殊的意義,但在實際拆卸九連環的操做中,因爲9是奇數,記得第一步是OFF 1
,也就是拆下第1環。