很高興能和大家一起共同學習演算法導論這本書。筆者將在業餘時間把演算法導論後面的題解以博文的形式展現出來希望能得到大家的支援謝謝。如果有可能我會做一些教學視訊免費的供大家觀看。
練習題選自演算法導論中文第三版第6頁中的練習。
1.1-1 給出現實生活中需要排序的一個例子或者現實生活中需要計算凸殼的一個例子。
這個問題有倆個子問題。我一一解答:
(1) 首先是排序,日常需要排序的地方很多,例如今日微博熱搜等等這個不用細說了。
(2)但是關於第二個問題我需要多寫一點。
第一這本書的翻譯的地方有誤,凸殼在這裡指的是計算幾何中的多邊形凸包問題。
下面摘選自百度百科。
⒈對於一個集合D,D中任意有限個點的凸組合的全體稱為D的凸包。 ⒉對於一個集合D,所有包含D的凸集之交稱為D的凸包。 可以證明,上述兩種定義是等價的 概念 示例圖(一) 示例圖(一) 1 點集Q的凸包(convex hull)是指一個最小凸多邊形,滿足Q中的點或者在多邊形邊上或者在其內。右圖中由紅色線段表示的多邊形就是點集Q={p0,p1,...p12}的凸包。 2 一組平面上的點,求一個包含所有點的最小的凸多邊形,這就是凸包問題了。這可以形象地想成這樣:在地上放置一些不可移動的木樁,用一根繩子把他們儘量緊地圈起來,並且為凸邊形,這就是凸包了。 數學定義:設S為歐幾里得空間 的任意子集。包含S的最小凸集稱為S的凸包,記作conv(S)
凸包問題在實際中的應用很廣泛,它可以應用於冶金術、城市規劃、影像處理、統計學等等多個領域。
1.1-2 除速度外,在真實環境中還可能使用哪些其他有關效率的量度?
學過高中物理的都知道有功率吧。實際生產中還有開發效率,生產效率。
別的筆者暫時也想不出來。
1.1-3 選擇一種你以前已知的資料結構並討論其優勢和侷限。
筆者在這裡列舉一個圖的資料結構-------鄰接矩陣。並以PAT練習平臺中的某一道題來舉例子。
首先介紹一下鄰接矩陣:(圖畫的不咋好請諒解)
在這裡 我們完全可以用一個矩陣來將右邊的無向圖的節點和節點之間的關係完美的表現出來,但是當我們的節點過多,而關係少的時候,這個鄰接矩陣就顯得過於臃腫了,所以我們可以總結出以下倆點:
1)鄰接矩陣的優勢在於描述通俗易懂,演算法實現起來簡單,在稠密矩陣中效率依然很高。
2)鄰接矩陣的侷限性在於在處理的節點過多的時候(即稀疏矩陣),無論是時間複雜度還是空間複雜度均過高。
下面這道題是一道練手的簡單題,有興趣的朋友可以去做一下來感受一下鄰接矩陣和稀疏矩陣的不同。
這道題如果你認真的去做了,你就會發現。雖然鄰接矩陣無論是在演算法實現上還是結構都很簡單,但是無論如何也不能避免他在遍歷的時候的時間複雜度過高,(一般都是O^2級別)。
因此一般在處理稀疏矩陣的時候,我們一般選擇鄰接表的實現方法去替代鄰接矩陣的實現方法。
1.1-4 前面給出的最短路徑與旅行商問題有哪些相似之處又有哪些不同?
旅行商問題簡而言之就是選出所有可能的候選路徑,而非最短路徑。
它們是相似的,因為每個人都必須走一個圖並在其中找到一條路徑。
他們又是不同的,最短路徑僅需要兩點之間的路徑,而旅行推銷員需要在返回第一點的更多點之間的路徑。
至於如何尋找最短路徑最簡單的方法就是進行BFS(寬度優先遍歷)。
下面是摘取百度百科的介紹
已知圖G=(V,E)和一個源頂點s,寬度優先搜尋以一種系統的方式探尋G的邊,從而“發現”s所能到達的所有頂點,並計算s到所有這些頂點的距離(最少邊數),該演算法同時能生成一棵根為s且包括所有可達頂點的寬度優先樹。對從s可達的任意頂點v,寬度優先樹中從s到v的路徑對應於圖G中從s到v的最短路徑,即包含最小邊數的路徑。該演算法對有向圖和無向圖同樣適用。
之所以稱之為寬度優先演算法,是因為演算法自始至終一直通過已找到和未找到頂點之間的邊界向外擴充套件,就是說,演算法首先搜尋和s距離為k的所有頂點,然後再去搜尋和S距離為k+l的其他頂點。
通俗點說,就是在每一次遍歷的時候,將每個子節點放入一個佇列中,然後再不斷遞迴以此尋找最短路徑。
對於最短路徑的尋找方法還有倆種最經典的。
1)Dijkstra(迪傑斯特拉)演算法
他的演算法思想是按路徑長度遞增的次序一步一步併入來求取,是貪心演算法的一個應用,用來解決單源點到其餘頂點的最短路徑問題。
演算法思想
首先,我們引入一個輔助向量D,它的每個分量D[i]表示當前找到的從起始節點v到終點節點vi的最短路徑的長度。它的初始態為:若從節點v到節點vi有弧,則D[i]為弧上的權值,否則D[i]為∞,顯然,長度為D[j] = Min{D[i] | vi ∈V}的路徑就是從v出發最短的一條路徑,路徑為(v, vi)。
那麼,下一條長度次短的最短路徑是哪一條呢?假設次短路徑的終點是vk,則可想而知,這條路徑或者是(v, vk)或者是(v, vj, vk)。它的長度或者是從v到vk的弧上的權值,或者是D[j]和從vj到vk的權值之和。
一般情況下,假設S為已知求得的最短路徑的終點集合,則可證明:一下條最短路徑(設其終點為x)或者是弧(v, x)或者是中間只經過S中的頂點而最後到達頂點x的路徑。這可用反證法來證明,假設此路徑上有一個頂點不在S中,則說明存在一條終點不在S中而長度比此路徑短的路徑。但是這是不可能的。因為,我們是按路徑常度的遞增次序來產生個最短路徑的,故長度比此路徑端的所有路徑均已產生,他們的終點必定在S集合中,即假設不成立。
因此下一條次短的最短路徑的長度是:D[j] = Min{D[i] | vi ∈ V - S},其中,D[i]或者是弧(v, vi)的權值,或者是D[k](vk ∈ S)和弧(vk, vi)上權值之和。
2)Floyd(弗洛伊德)演算法
Floyd演算法是一個經典的動態規劃演算法。是解決任意兩點間的最短路徑(稱為多源最短路徑問題)的一種演算法,可以正確處理有向圖或負權的最短路徑問題。(動態規劃演算法是通過拆分問題規模,並定義問題狀態與狀態的關係,使得問題能夠以遞推(分治)的方式去解決,最終合併各個拆分的小問題的解為整個問題的解。)
演算法思想
從任意節點i到任意節點j的最短路徑不外乎2種可能:1)直接從節點i到節點j,2)從節點i經過若干個節點k到節點j。所以,我們假設arcs(i,j)為節點i到節點j的最短路徑的距離,對於每一個節點k,我們檢查arcs(i,k) + arcs(k,j) < arcs(i,j)是否成立,如果成立,證明從節點i到節點k再到節點j的路徑比節點i直接到節點j的路徑短,我們便設定arcs(i,j) = arcs(i,k) + arcs(k,j),這樣一來,當我們遍歷完所有節點k,arcs(i,j)中記錄的便是節點i到節點j的最短路徑的距離。(由於動態規劃演算法在執行過程中,需要儲存大量的臨時狀態(即小問題的解),因此它天生適用於用矩陣來作為其資料結構,因此在本演算法中,我們將不使用Guava-Graph結構,而採用鄰接矩陣來作為本例的資料結構)