參考文章:
李卿. 遞歸算法分析中主定理的應用[J]. 黑龍江科技信息, 2011(29):97+207.
Thomas H.Cormen,Charles E.Leiserson,Ronald L.Rivest,Clifford Stein. 殷建平等譯. 算法導論第三版 [M]. 北京:機械工業出版社,2013,55-58.
前言:
本篇文章與我的 博客園 同步更新。
在此之前,請先閱讀 【洛谷日報#33】時空復雜度分析及master定理,其中關於時間復雜度表示的基礎知識不再闡述。
引出:
現在考慮一個問題:假設某算法的計算時間表示為遞歸式:
求該算法的時間復雜度。
當給你拋出這么一個題型時,你怎么辦?
憑經驗和感覺蒙
小幾率能蒙對,但你覺得這種題CCF會送你分嗎?
遞歸進去
像這樣遞歸進去:
每項都 \(n\div 2\),總共遞歸 \(\log_2 n\) 層:
即 \(T(n)=\Theta(n\log^2 n)\)。
這么做不是沒有道理,但是如果 \(T(n)=3T(\frac{n}{4})+n\log n\),用這種方法根本算不出來(或許可以算出來,但是操作極其麻煩)。
主定理(master定理)求解
主定理:\(a,b\) 是常數,\(f(n)\) 為額外附加值函數\(T(n)\) 為遞歸式 \(T(n)=aT(\frac{n}{b})+f(n)\quad(a>0,b>1)\),就有:
- 當 \(f(n)=\mathcal{O}(n^{(\log_ba)-\epsilon})\) 其中 \(\epsilon>0\) 是一個常數(相當於 \(\log_ba>f(n)\)),則有 \(T(n)=\Theta(n^{\log_ba})\);
- 當 \(f(n)=\Theta(n^{\log_ba})\),則有 \(T(n)=\Theta(n^{\log_ba}\log n)\);
- 當 \(f(n)=\Omega(n^{(\log_ba)+\epsilon})\) 其中 \(\epsilon>0\) 是一個常數(相當於 \(\log_ba<f(n)\)),且對於一個常數 \(c<1\) 和所有足夠大的 \(n\) 有 \(af(\frac{n}{b})\leq cf(n)\)(這一條件在這里可以暫時忽略不看,但在證明時起到至關重要的作用),則有 \(T(n)=\Theta(f(n))\).
- 當 \(f(n)=\Theta(n^{\log_ba}\log^kn)\) 其中 \(k\geq1\) 是一個常數,則有 \(T(n)=\Theta(n^{\log_ba}\log^{k+1}n)\);
這么看着有點枯燥乏味的樣子,不利於理解,但如果丟掉定理四的話(畢竟CSP/NOIp好像真的沒考過定理四,其實可以發現定理二和定理四其實是同一種,便於萌新理解就分開了),主定理的定義可以直接寫成:
(圖一)
也就是 \(n^{\log_ba}\) 與 \(f(n)\) 進行比較!
圖一、算法導論和上面提過的論文沒有提到過定理四,但是原來那篇日報(#33)有,對此我想說,洛谷日報真是太好了!導論不行!日報行!(老伏拉夫了
舉例說明:
例一:\(T(n)=4T(\frac{n}{2})+n\),此時 \(a=4,b=2,\epsilon=1\),那么 \(\log_ba=\log_24=2,f(n)=\mathcal{O}(n^{\log_ba-\epsilon})=\mathcal{O}(n^{2-1})\),\(f(n)\) 成立,所以 \(T(n)=\Theta(n^{\log_ba})=\Theta(n^2)\)。
例二:\(T(n)=2T(\frac{n}{2})+n\),此時 \(a=2,b=2\),那么 \(\log_ba=\log_22=1,f(n)=\Theta(n^{\log_ba})=\Theta(n)\),\(f(n)\) 成立,所以 \(T(n)=\Theta(n^{\log_ba}\log n)=\Theta(n\log n)\)。
例三:\(T(n)=4T(\frac{n}{2})+n^3\),此時 \(a=4,b=2,\epsilon=1\),那么 \(\log_ba=\log_24=2,f(n)=\Omega(n^{\log_ba+\epsilon})=\Omega(n^{2+1})\),對於 \(c=\frac{2}{3}\) 和夠大的 \(n\),\(\left(af(\frac{n}{b})=4(\frac{n}{2})^3=4(\frac{n^3}{8})=\frac{n^3}{2}\right)\leq \left(cf(n)=\frac{2n^3}{3}\right)\),\(f(n)\) 成立,所以 \(T(n)=\Theta(f(n))=\Theta(n^3)\)。
例四:\(T(n)=2T(\frac{n}{2})+n\log n\),此時 \(a=2,b=2,k=1\),那么 \(\log_ba=\log_22=1,f(n)=\Theta(n^{\log_ba}\log^kn)=\Theta(n\log n)\),\(f(n)\) 成立,所以 \(T(n)=\Theta(n^{\log_ba}\log^{k+1}n)=\Theta(n\log^2 n)\)。
證明:
先聲明:證明又長又臭,有億點點難理解,學有余力的 dalao 可以來康康。
俗話說得好:“欲要證明master,就先畫棵遞歸樹”:
(圖二)
關於圖二的解釋及證明:
對於第 \(i\) 層(\(i\ne \log_bn\)),有 \(a^i\) 個節點,而每個節點的值是 \(f(\frac{n}{b^i})\),那么第 \(i\) 層總共的值是 \(a_if(\frac{n}{b^i})\)。
對於第 \(\log_bn\) 層,有 \(a^{\log_bn}\) 個節點,而每個節點的時間復雜度是 \(\Theta(1)\),那么這一層總共的時間復雜度是 \(\Theta(a^{\log_bn})=\Theta(n^{\log_ba})\) 層。
對於 \(a^{\log_bn}=n^{\log_ba}\) 的證明:
\(a^{\log_bn}=n^{\log_ba}\) 得證。
這么看,圖二的遞歸樹的總時間復雜度為 \(T(n)=\Theta(n^{\log_ba})+\sum_{j=0}^{\log_bn-1}a^jf(\frac{n}{b^j})\),就是葉子節點層加上其它結點層的值。
證明*:
根據上文這個 \(T(n)\) 的時間復雜度,我們定義一個函數 \(g(n)\):
這個 \(g(n)\) 有一些性質:
- 當 \(f(n)=\mathcal{O}(n^{(\log_ba)-\epsilon})\) 其中 \(\epsilon>0\) 是一個常數,則有 \(g(n)=\mathcal{O}(n^{\log_ba})\);
- 當 \(f(n)=\Theta(n^{\log_ba})\) 時,則有 \(g(n)=\Theta(n^{\log_ba}\log n)\);
- 當 \(f(n)=\Omega(n^{(\log_ba)+\epsilon})\) 其中 \(\epsilon>0\) 是一個常數,且對於一個常數 \(c<1\) 和所有足夠大的 \(n\) 有 \(af(\frac{n}{b})\leq cf(n)\),則有 \(g(n)=\Theta(f(n))\).
- 當 \(f(n)=\Theta(n^{\log_ba}\log^kn)\) 其中 \(k\geq1\) 是一個常數,則有 \(g(n)=\Theta(n^{\log_ba}\log^{k+1}n)\);
欸!有沒有發現好像在哪見過!那是因為這是我從上文復制下來的(
證明關於g函數性質*:
性質 1:
將 \(f(n)=\mathcal{O}(n^{(\log_ba)-\epsilon})\) 代入進 \(g(n)=\sum_{j=0}^{\log_bn-1}a^jf(\frac{n}{b^j})\):
然后根據等比數列求和公式化簡 \(\sum_{j=0}^{\log_bn-1}(b^\epsilon)^j\):
這里回想一下 \(b,\epsilon\) 的定義,(做到不忘初心牢記使命),它們是常數,所以式子中 \(\frac{1}{b^{\epsilon}-1}\) 也是常數,應忽略:
性質 1 得證。
性質 2:
性質 1 和性質 2 操作一樣,就是一直代入再一直化簡,將 \(f(n)=\Theta(n^{\log_ba})\) 代入進 \(g(n)=\sum_{j=0}^{\log_bn-1}a^jf(\frac{n}{b^j})\):
注意:這里重頭戲來了!式子中的 \(\log_bn\) 是可以直接改底數的,因為可以通過換底公式得到對數函數都是同級的。因此我們可以把 \(b\) 改成 \(2\)(即 \(\log_bn\) 化成 \(\log n\)):
性質 2 得證。
性質 3:
性質 3 是最特殊的,用 \(af(\frac{n}{b})\leq cf(n)\) 遞歸 \(j\) 次可以得到 \(a^j f(\frac{n}{b^j})\leq c^j f(n)\)。再用這個式子套 \(g(n)\) 定義:
解釋一下上面的式子,因為 \(c\) 都是正數,所以如果 \(g(n)\leq f(n)\sum_{j=0}^{\log_bn-1}c^j\),顯然 \(g(n)\leq f(n)\sum_{j=0}^{\infty}c^j\)。而這么做是為了更好證明。
接下來還是用等比數列求和公式化簡:
你可能好奇這個等比數列求和是怎么化的,下面證明一下:
設 \(S=c^0+c^1+c^2+\cdots+c^{\infty}\) 表示 \(\sum_{j=0}^{\infty}c^j\),此時公比為 \(c\):
\(cS=c^1+c^2+c^3+\cdots+c^{\infty}\),這里 \(\infty+1=\infty\)。
\((1-c)S=c^0=1\)
\(S=\frac{1}{1-c}\)
即 \(\sum_{j=0}^{\infty}c^j=\frac{1}{1-c}\)。
回到題目,由 \(g(n)\leq\left(\frac{1}{1-c}\right)f(n)\) 得到 \(g(n)=\mathcal{O}(f(n))\)。
而根據 \(g(n)\) 的定義 \(g(n)=f(n)+af(\frac{n}{b})+a^2f(\frac{n}{b^2})+\cdots+a^{\log_bn-1}f(\frac{n}{b^{\log_bn-1}})\geq f(n)\),得到 \(g(n)=\Omega(f(n))\)。
所以 \(g(n)=\Theta(f(n))\)。
性質 3 得證。
性質 4:
老套路,將 \(f(n)=\Theta(n^{\log_ba}\log^kn)\) 代入進 \(g(n)=\sum_{j=0}^{\log_bn-1}a^jf(\frac{n}{b^j})\):
和性質 2 一樣: \(\log_bn\) 可以直接化為 \(\log n\)。然后 \(-n^{\log_ba}\sum_{j=0}^{\log_bn-1}\log^k b^j\) 是一個負數,在時間復雜度的表示中可以忽略,所以得到:
性質 4 得證。
主定理總時間復雜度證明:
回到圖二的總時間復雜度 \(T(n)=\Theta(n^{\log_ba})+\sum_{j=0}^{\log_bn-1}a^jf(\frac{n}{b^j})\)。
當 \(f(n)=\mathcal{O}(n^{(\log_ba)-\epsilon})\) 時:
當 \(f(n)=\Theta(n^{\log_ba})\) 時:
當 \(f(n)=\Omega(n^{(\log_ba)+\epsilon})\),且對於一個常數 \(c<1\) 和所有足夠大的 \(n\) 有 \(af(\frac{n}{b})\leq cf(n)\):
當 \(f(n)=\Theta(n^{\log_ba}\log^kn)\) 時:
主定理證畢。
后記 & 感謝名單:
在這篇文章證明的主定理只是對於 \(b\) 的冪下的,就是說向上、向下取整的沒有證明,但要證明這些實在太難了,要花費更長的時間 (主要還是懶。
我在查找資料的時候發現還有一種定理——Akra-Bazzi定理(打開要梯子)也是時間復雜度的。