\( \newcommand{\ord}[1]{\mathcal{O}\left(#1\right)} \newcommand{\abs}[1]{\lvert #1 \rvert} \newcommand{\floor}[1]{\lfloor #1 \rfloor} \newcommand{\ceil}[1]{\lceil #1 \rceil} \newcommand{\opord}{\operatorname{\mathcal{O}}} \newcommand{\argmax}{\operatorname{arg\,max}} \newcommand{\str}[1]{\texttt{"#1"}} \)
進階遞迴
遞迴大家都學過了,所以就用一些練習題來複習一下吧!
但是題目會比之前的還進階喔
九連環
九連環的規則
九連環一開始的時候有9個環,全部按順序套在一個柄上
每個環是互相牽制的,除了第1環,要取下或套上其他環是要在特定的狀態下才可以的,其規則有二:
規則一:第1環可以在任何時候套上或取下。
規則二:想套上或取下第N環 (N > 1),就必須將第 N-1 環套在柄上,而第 1 到 N-2 環全部取下,如此才能套上或取下第 N 環。
有沒有遞迴的感覺?
給大家3分鐘想想遞迴式吧
九連環的遞迴式
設\(in(n)\)為把前\(n\)個環套上所需的操作數,\(out(n)\)為把前\(n\)個環拿下所需的操作數,則:
$$in(n)=in(n-1)+out(n-2)+1+in(n-2)$$ $$out(n)=out(n-2)+1+in(n-2)+out(n-1)$$ 當\(n=1\)時,\(in(n)=out(n)=1\)
可以寫程式了!
八皇后問題
八皇后問題
在 8x8 的西洋棋棋盤上擺放八隻皇后,讓他們恰好無法互相攻擊對方,為了達到此目的,任兩個皇后都不能處於同一條橫行、縱行或斜線上。
目標是要算有幾種排列方式
想法
把所有的情況列出來吧
小心TLE喔
有趣的性質
應該對八皇后的解法很有幫助吧
merge sort
排序左半,排序右半,合併
大家應該知道std::sort()吧?
雖然很方便但是大家應該還是要學一下merge_sort
因為這次的作業會用到!
預備知識
序列合併問題
sorted array merge problem
給你兩個已經排序好的陣列\(A\)和\(B\)
請將這兩個陣列合併成一個排序好的陣列\(res\)
例如:
$$A=\{1,3,5,7\}$$ $$B=\{2,4,7,9,16,20\}$$ 則經過此算法後 $$res=\{1,2,3,4,5,7,7,9,16,20\}$$
有沒有什麼很快的作法?
很快的作法
合併的時候每次拿最小的,不過因為兩個陣列都已經被排序好,所以至多只需要檢查兩個元素
分析
因為每次只比較兩個元素,而且$A,\;B$兩陣列都會被存到$res$裡面,所以最多會執行約$\abs{A}+\abs{B}$次操作
正題
我們可以利用
序列合併問題
來排序:
把一個序列從中間切分成兩個序列,將兩個序列排序完後合併
如果切分的序列長度>1,則繼續按此方法排序
這句話有沒有遞迴的感覺?
仔細看這過程,會發現每次都是把序列從中間切開,直到剩下一個元素為止
這樣做的話,會發現整棵樹的深度為$\ceil{log_2(n)}$
每一層有$n$個元素,用merge合併的話操作次數為$n$次
因此總共約會有$n*\ceil{log_2(n)}$次操作
merge sort的影片
分治法
Divide & Conquer
像這種把要算的東西分成很多份(不一定是分兩半),分別把那幾分遞迴處理完之後,在合併成原來的答案
這種做法就稱為分治法
這次的作業中有分治法的題目喔
至於要怎麼分治就留給你們想像吧
遞迴題目
遞迴題目
Recursion
九連環
八皇后
看著數列的卦長