1. 程式人生 > >演算法分析與設計基礎 (清華版)

演算法分析與設計基礎 (清華版)

Taken from "Introduction to The Design and Analysis of Algorithms" by Anany Levitin 節選自《演算法設計與分析基礎》潘彥 譯 蠻力法 就像寶劍不是撬棍一樣,科學也很少使用蠻力。
——Edward Lytton (1830 - 1873),leila,第二卷,第一章 認真做事常常是浪費時間。
——Robert Byrne,撞球大師,檯球選手和作家 人們是這樣描述它的:蠻力法是一種簡單直接地解決問題的方法,常常直接基於問題的描述和所涉及的概念定義。這裡的“力”是指計算機的能“力”, 而不是人的智“力”。我們也可以用“直接做吧!”來描述蠻力法的策略。而且一般來說,蠻力策略也常常是最容易應用的方法。雖然巧妙和高效的演算法很少來自於 蠻力法,但我們不應該忽略它作為一種重要的演算法設計策略的地位。第一,和其他某些策略不同,我們可以應用蠻力法來解決廣闊領域的各種問題(實際上,它可能 是惟一一種幾乎什麼問題都能解決的一般性方法)。具體來說,蠻力法常常用於一些非常基本、但又十分重要的演算法,比如計算n個數字的和,求一個列表的最大元 素,等等。第二,對於一些重要的問題來說(比如:排序、查詢、矩陣乘法和字串匹配),蠻力法可以產生一些合理的演算法,它們多少具備一些實用價值,而且並 不限制例項的規模。第三,如果要解決的問題例項不多,而且蠻力法可以用一直能夠接受的速度對例項求解,那麼,設計一個更高效演算法所花費的代價很可能是不值 得的。第四,即使效率通常很低,仍然可以用蠻力演算法解決一些小規模的問題例項。最後,一個蠻力演算法可以為研究或教學目的服務,例如,它可以作為準繩,來衡 量同樣問題的更高效演算法。 下列這些著名的演算法可以看作是蠻力法的例子:基於定義的矩陣乘法演算法;選擇排序;順序查詢;簡單的字串匹配演算法。窮舉查詢是解組合問題的一種 蠻力方法。它要求生成問題中的每一個組合物件,選出其中滿足該問題約束的物件,然後找出一個期望的物件。旅行商問題、揹包問題和分配問題是典型的能夠用窮 舉查詢演算法求解的問題,至少在理論上是這樣的。除了相關問題的一些規模非常小的例項,窮舉查詢法幾乎是不實用的。 分治法
無論人們在祈禱什麼,他們總是在祈禱一個奇蹟。每一個祈禱都可以簡化為:偉大的上帝呀,請讓兩個二相加不等於四吧。
——伊萬·屠格涅夫(1818 - 1883),俄國作家和短篇小說家 分治法可能是最著名的通用演算法設計技術了。雖然它的名氣可能和它那好記的名字有關,但它的確是當之無愧的:很多非常有效的演算法實際上是這個通用演算法的特殊實現。其實,分治法是按照以下方案工作的:
  • 將問題的例項劃分為同一個問題的幾個較小的例項,最好擁有同樣的規模。
  • 對這些較小的例項求解(一般使用遞迴方法,但在問題規模足夠小的時候,有時也會使用一些其他方法)。
  • 如果必要的話,合併這些較小問題的解,以得到原始問題的解。

不是所有的分治演算法都一定比簡單蠻幹更有效。但是,通常我們向演算法女神所做的祈禱都被應允了,因而,使用分治法往往比使用其他方法效率更高。實際 上,分治法孕育了電腦科學中許多最重要和最有效的演算法。雖然我們通常只考慮順序演算法,但要知道,分治法對於並行演算法是非常理想的,因為各個子問題都可以 由不同的CPU同時計算。許多分治演算法的時間效率T(n)滿足方程T(n)=aT(n/b)+f(n)。

一些應用分治法的案例: 合併排序是一種分治排序演算法。它把一個輸入陣列一分為二,並對它們遞迴排序,然後把這兩個排好序的子數組合併為原陣列的一個有序排列。在任何情 況下,這個演算法的時間效率都是Θ(nlogn),而且它的鍵值比較次數非常接近理論上的最小值。它的主要缺點是需要相當大的額外儲存空間。
快速排序是一種分治排序演算法,它根據元素值和某些事先確定的元素的比較結果,來對輸入元素進行分割槽。快速排序十分有名,這不僅因為對於隨機排列的陣列,它是一種較為出眾的nlogn效率演算法,而且因為它的最差效率是平方級的。
折半查詢是一種對有序陣列進行查詢O(logn)效率演算法。它是應用分治技術的一個非典型案例,因為在每次迭代中,它只需要解決兩個問題的一個。
二叉樹的經典遍歷演算法——前序、中序、後序和其他類似的演算法都需要遞迴處理左右兩棵子樹,它們都可以當作是分治技術的例子。用一些特定的外部頂點來替代給定樹的空子樹,有助於對這些演算法進行分析。
有一種處理兩個n位整數相乘的分治演算法,大約需要做n(index:1.585)次一位數乘法。
Strassen演算法只需要做7次乘法就能計算出兩個2桔方陣的積,但比基於定義的演算法要做更多次的加法。利用分治技術,該演算法計算兩個n階方陣的積,但 比基於定義的演算法要做更多次的加法。利用分治技術,該演算法計算兩個n階方陣的乘法時需要做n(index:2.807)次乘法。
分治技術可以成功地應用於兩個重要的計算幾何問題:最近對問題和凸包問題。 減治法
普盧塔克說,薩特斯為了告訴他的士兵堅忍和智慧比蠻力更重要的道理,把兩匹馬帶到他們面前,然後讓兩個人拔光馬的尾毛。一個人是魁梧的大力士, 他用力地拔了又拔,但一點效果也沒有;另一個人是一個精美的、長相矯捷的裁縫,他微笑著,每次拔掉一根毛,很快就把尾巴拔得光禿禿的。
——E. Cobham Brewer,《慣用語和寓言詞典》,1898 減治技術利用了一種關係:一個問題給定例項的解和同樣問題較小例項的解之間的關係。一旦建立了這樣一種關係,我們既可 以從頂至下(遞迴地),也可以從底至上(非遞迴地)地來運用。減治法有3種主要的變種:
  • 減去一個常量;
  • 減去一個常數因子;
  • 減去的規模是可變的。
在減常量變種中,每次演算法迭代總是從例項規模中減去一個規模相同的常量。一般來說,這個常量等於一,但減二的情況偶爾也會發生,例如,有的演算法會根據例項規模為奇數和偶數的不同情況,分別做不同的處理。
減常因子技術意味著在演算法的每次迭代中,總是才例項的規模中減去一個相同的常數因子。在大多數應用中,這樣的常數因子等於二。
最後,在減治法的減可變規模變種中,演算法在每次迭代時,規模減小的模式都是不同的。計算最大公約數的歐幾里德演算法是這種情況的一個很好的例子。回想一下,這個演算法是基於這個公式的:
gcd(m,n)=gcd(n,m mod n)
雖然等號右邊的那些引數總是小於等號左邊的引數(至少從該演算法的第二次迭代開始),但它們既不是以常數也不是以常數因子的方式減小的。 一些應用減治法的案例: 插入排序是減(減一)治技術在排序問題上的直接應用。無論在平均情況還是最差情況下,它都是一個Θ(n2)的演算法,但在平均情況下的效率大約要比最差情況快兩倍。該演算法一個較為出眾的優勢在於,對於幾乎有序的陣列,它的效能是很好的。
深度優先查詢(DFS)和廣度優先查詢(BFS)是兩種主要的圖遍歷演算法。通過把圖表示成深度優先森林或者廣度優先森林的形式,有助於對圖的許多重要特性 進行研究。兩種演算法都有著相同的時間效率:對於鄰接矩陣表示法來說是Θ(|V|2);對於鄰接連結串列表示法來說是Θ(|V|+|E|)。
一個有向圖是一個對邊指定了方向的圖。拓撲排序要求按照這種次序列出它的頂點,使得對於圖中每一條邊來說,邊的起始頂點總是排在邊的結束頂點之前。當且僅當有向圖是一個無環有向圖(不包含迴路的有向圖)的時候,該問題有解,也就是說,它不包含有向的迴路。
解決拓撲排序問題有兩種演算法。第一種演算法基於深度優先查詢;第二種演算法基於減一技術的直接應用。
在設計生成基本組合物件的演算法時,減一技術是一種非常自然的選擇。這類演算法中最高效的型別是最小變化演算法。然而,組合物件的數量增長地如此之快,使得實際應用中,即使最高效的演算法也只能用來解決這類問題的一些非常小的例項。
有些問題是能夠用減常因子演算法來解的,這樣的例子包括:用天平來辨別假幣、俄式乘法以及約瑟夫斯問題。其他兩個更重要的例子是折半查詢和用平方求冪。
對於某些基於減治技術的演算法,在演算法的一次迭代和另一次迭代時消減的規模是變化的。這種減可變規模演算法的例子包括歐幾里德演算法、選擇問題的基於分割槽的演算法、插值查詢和二叉查詢樹中的查詢和插入操作。 變治法 生活的祕密在於。。。用一個煩惱代替另一個煩惱。
——Charles M. Schulz (1922 - 2000),美國漫畫家,史努比之父 這種設計方法基於變換的思想,稱為變治法。因為這些方法都是分成兩個階段工作的。首先,在“變”的階段,出於這樣或者那樣的原因,把問題的例項 變得更容易求解。然後,在第二階段或者說“治”的階段,對例項進行求解。根據我們對問題例項的變換方式,變治思想有3種主要的型別:
  • 變換為同樣問題的一個更簡單或者更方便的例項——我們稱之為例項化簡;
  • 變換為同樣問題的不同表現——我們稱之為改變表現。
  • 變換為另一個問題的例項,這種問題的演算法是已知的——我們稱之為問題化簡。
一些應用變治法的案例: 堆是一棵基本完備二叉樹,它的鍵都滿足父母優勢要求。雖然定義為二叉樹,但一般用陣列來實現堆。堆對於優先佇列的高效實現來說尤為重要;同時,堆還是堆排序的基礎。
堆排序在理論上是一種重要的排序演算法,它的基本思路是,在排好堆中的陣列元素後,再從剩餘的堆中連續刪除最大的元素。 無論在最差情況下還是在平均情況下,該演算法的執行時間都屬於Θ(nlogn),而且,它還是在位的排序演算法。
AVL樹是一種在二叉樹可能達到的廣度上儘量平衡的二叉查詢樹。平衡是由四種稱為旋轉的變換來維持的。AVL樹上的所有基本操作都屬於Θ(logn);它消除了經典二叉查詢樹在最差效率上的弊端。
2-3樹是一種達到了完美平衡的查詢樹,它允許一個節點最多包含兩個鍵和三個子女。這個思想推而廣之,會產生一種非常重要的B樹。
高斯消去法是一種解線性方程組的演算法,它是線性代數中的一種基本演算法。它通過把方程組變換為反向替換法求解。高斯消去法大約需要1/3n3次乘法運算。
在無需對係數進行預處理的多項式求解演算法中,霍納法則是最優的。它只需要n次乘法和n次加法。它還有一些有用的副產品,比如綜合除法演算法。
兩種計算a(index:n)的二進位制冪演算法。它們使用了指數n的二進位制表示,但它們按照相反的方向對其進行處理:從左到右和從右到左。
線性規劃關心的是最優化一個包含若干變數的線性函式,這個函式受到一些形式為線性等式和線性不等式的約束。有一些高效的演算法可以對這個問題的龐大例項求 解,它們包含了成千上萬的變數和約束,但不能要求變數必須是整數。如果變數一定要是整數,我們稱之為整數線性規劃問題,這類問題的難度要高很多。 時空權衡 最重要的事情永遠不能受次要事情的支配。
——Johnn Wolfgang von Goethe (1749 - 1832) 無論對於計算機理論工作者還是計算機實踐工作者來說,演算法設計中的時空權衡都是一個總所周知的問題。作為一個例子,考慮一下在函式定義域的多個 點上計算函式值的問題。如果運算時間更為重要的話,我們可以事先把函式值計算好並將它們儲存在一張表中。這就是在電子計算機發明前,“人工計算機”所做的 工作,那時的圖書館也被厚重的數學用表堆滿了。雖然隨著電子計算機的廣泛應用,這些數學用表失去了大部分的吸引力,但事實正面,在開發一些用於其他問題的 重要演算法時,它們的基本思想還是非常有用的。按照一種更一般的表述,這個思想是對問題的部分或全部輸入做預處理,然後對獲得的額外資訊進行儲存,以加速後 面問題的求解。我們把這個方法稱為輸入增強。其他採用空間換時間權衡思想的技術簡單地使用額外空間來實現更快和(或)更方便的資料存取。我們把這種方法稱 為預構造。這個名字強調了這種空間換時間權衡技術的兩個方面:所討論問題在實際處理之前,已經做過某些處理了;但和輸入增強技術不同,這個技術只涉及存取 結構。還有一種和空間換時間權衡思想相關的演算法設計技術:動態規劃。這個策略的基礎是把給定問題中重複子問題的解記錄在表中,然後求得所討論問題的解。
最後還要對演算法設計中時間和空間的相互作用作兩點說明:首先,並不是在所有的情況下,時間和空間這兩種資源都必須相互競爭。實際上,它們可以聯合起來,使 得一個演算法無論在執行時間上還是消耗的空間上都達到最小化。具體來說說,這種情況出現在一個演算法使用了一種空間效率很高的資料結構來表示問題的輸入,這種 結構又反過來提高演算法的時間效率。作為一個例子,考慮一下圖的遍歷問題。回憶一下兩種主要的遍歷演算法(深度優先查詢和廣度優先查詢),它們搜時間效率依賴 於表示圖的資料結構:對於鄰接矩陣表示法是Θ(n2),對於鄰接連結串列表示法是Θ(n+m),其中n和m分別是頂點和邊的數量。如果輸入圖是稀疏的,也就是 說,相對於頂點的數量來說,邊的數量並不多(比方說,m∈O(n)),無論從空間角度還是從執行時間的角度來看,鄰接連結串列表示法的效率都會更高一些。在處 理稀疏矩陣和稀疏多項式的時候也會有相同的情況:如果在這些物件中,0所佔的百分比足夠高,在表示和處理物件時把0忽略,我們既可以節約空間也可以節約時 間。
其次,在討論空間換時間權衡的時候,我們無法不提到資料壓縮這個重要領域。然而,我們必須強調,資料壓縮的主要目的是節約空間而不是作為解決另一個問題的一項技術。 一些應用時空權衡的案例: 分佈計數是一種特殊的方法,用來對元素取值來自於一個小集合的列表排序。
用於串匹配的Horspool演算法可以看作是Boyer-Moore演算法的一個簡化版本。兩個演算法都以輸入增強思想為基礎,並且從右向左比較模式中的字元。兩個演算法都是用同樣的壞符合移動表;Boyer-Moore演算法還使用了第二個表,稱為好字尾移動表。
雜湊是一種非常高效的實現字典的方法。它的基本思想是把鍵對映到一張一維表中。這種表在大小上的限制使得它必須採用一種碰撞解決機制。雜湊的兩種主要型別 是開雜湊又稱為分離鏈(鍵儲存在散列表以外的連結串列中)以及閉雜湊又稱為開式定址(鍵儲存在散列表中)。平均情況下,這兩種演算法的查詢、插入和刪除操作的效 率都是屬於Θ(1)的。
B樹是一顆平衡查詢樹,它把2-3樹的思想推廣到允許多個鍵位於同多節點一個節點上。它的主要應用是維護儲存在磁碟上的資料的類索引資訊。通過選擇恰當的樹的次數,即使對於非常大的檔案,我們所實現的查詢、插入和刪除操作也只需要執行很少幾次的磁碟存取。 動態規劃 思想,就像幽靈一樣……在它自己解釋自己之前,必須先告訴它些什麼。
——查爾斯·狄更斯(1812-1870) 動態規劃(dynamic programming)是一種演算法設計技術,它有著相當有趣的歷史。作為一種使多階段決策過程最優的通用方法,它是在20世紀50年代由一位卓越的美國 數學家Richard Bellman所發明的。因此,這個技術名字中的"programming"是計劃和規範的意思,不是代表計算機中的程式設計。它作為一種重要的工具在應用數 學中的價值被大家認同以後,起碼在電腦科學的圈子裡,人們不僅用它來解決特定型別的最優問題,而且最終把它作為一種通用的演算法設計技術來使用。在這裡, 我們正是從這個角度來考慮這種技術的。
如果問題是由交疊的子問題所構成的,我們就可以用動態規劃技術來解決它。一般來說,這樣的子問題出現在對給定問題求解的遞推關係中,這個遞推關係中包含了 相同型別的更小子問題的解。動態規劃法建議,與其對交疊的子問題一次又一次地求解,還不如對每個較小的子問題只求解一次並把結果記錄在表中,這樣就可以從 表中得出原始問題的解。一般來說,一個演算法如果基於經典從底向上動態規劃方法的話,需要解出給定問題的所有較小子問題。動態規劃法的一個變種試圖避免對不 必要的子問題求解,它利用了一種所謂的記憶功能,可以把它看作是動態規劃的一種從頂至下的變種。但無論我們使用動態規劃的經典從底至上版本還是它基於記憶 功能的從頂至下版本,設計這樣一種演算法的關鍵步驟還是相同的,即,匯出一個問題例項的遞推關係,該遞推關係包含該問題的更小(並且是交疊的)子例項的解。 對一個最優問題應用動態規劃方法要求該問題滿足最優性原則:一個最優問題的任何例項的最優解是由該例項的子例項的最優解組成的。 一些應用動態規劃的案例: 通過構造帕斯卡三角形來計算二項式係數可以看作是動態規劃技術在一個非最優問題上的應用。
求傳遞閉包的Warshall演算法和求完全最短路徑問題的Floyd演算法都基於同一種思想,可以把這種思想解釋為動態規劃技術的一種應用。
如果已知鍵的一個集合以及它們的查詢概率,可以使用動態規劃方法來構造一顆最優二叉查詢樹。
用動態規劃演算法求解揹包問題可以作為應用該技術對組合難題求解的例證。 貪婪技術 貪婪,我找不到一個更好的詞來描述它,它就是好!它就是對!它就是有效!
——美國演員邁克·道格拉斯,在影片《華爾街》中扮演Gordon Gecko時的臺詞 貪婪法建議通過一系列步驟來構造問題的解,每一步對目前構造的部分解做一個擴充套件,直到獲得問題的完整解為止。這個技術的核心是,所做的每一步選擇都必須滿足:
  • 可行的:即它必須滿足問題的約束。
  • 區域性最優:它是當前步驟中所有可行選擇中最佳的區域性選擇。
  • 不可取消:即選擇一旦做出,在演算法的後面步驟中就無法改變了。

這些要求對這種技術的名稱作出瞭解釋:在每一步中,它要求“貪婪”地選擇最佳操作,並希望通過一系列區域性的最優選擇,能夠產生一個整個問題的(全域性 的)最優解。我們儘量避免從哲學的角度來討論貪婪是好不好。(如果大家還沒有看過本章的引語中提到的那部電影,我可以告訴大家,影片中男主人公的結局並不 大好。)才我們演算法的角度來看,這個問題應該是,貪婪演算法是否是有效的。就像我們將會看到的,的確存在某些型別問題,一系列區域性的最優選擇對於它們的每一 個例項都能夠產生一個最優解。然而,還有一些問題並不是這種情況。對於這樣的問題,如果我們關心的是,或者說我們能夠滿足於一個近似解,貪婪演算法仍然是有 價值的。作為一種規則,貪婪演算法看上去既誘人又簡單。儘管看上去它們並不複雜,但在這種技術背後有著相當複雜的理論,它是基於一種被稱為“擬陣”的抽象組 合結構。

一些應用貪婪技術的案例: Prim演算法是一種為加權連通圖構造最小生成樹的貪婪演算法。它的工作原理是向前面構造的一顆子樹中新增離樹中頂點最近的頂點。
Kruskal演算法是另一種最小生成樹問題的演算法它按照權重的增序把邊包含進來,以構造一顆最小生成樹,並使得這種包含不會產生一條迴路。為了保證這種檢查的效率,需要應用一種所謂的union-find演算法。
Dijkstra演算法解決了單起點最短路徑問題,該問題要求出從給定的頂點(起點)出發通過加權圖或者有向圖的其他所有頂點的最短路徑。它的工作過程和Prim演算法是一樣的,不同點在於它比較的是路徑的長度而不是邊的長度。對於不含負權重的圖, Dijkstra演算法總是能夠產生一個正確的解。
哈夫曼樹是一顆二叉樹,它使得從根出發到包含一組預定義權重的葉子之間的加權路徑長度達到最小。哈夫曼樹的最重要的應用是哈夫曼編碼。
哈夫曼編碼是一種最優的自由字首變長編碼方案,它基於字元在給定文字中的出現頻率,把位元串賦給字元。這是通過貪婪地構造一顆二叉樹來完成的,二叉樹的葉子代表字母表中的字元,而樹中的邊則標記為0或者1。 回溯法和分支限界法 關注那些不斷已被他人成功應用的新思路。你的原創思想只應該應用在那些你正在研究的問題上。
——托馬斯·愛迪生(1847-1931) 回溯和分支限界都是以構造一顆狀態空間樹為基礎的,樹的節點反映了對一個部分解所作的特定選擇。如果可以保證,節點子孫所對應的選擇不可能得出 問題的一個解,兩種技術都會立即停止處理這個節點。兩種技術的區別在於它們能夠處理的問題型別不同。分支限界法只能應用於最優問題,因為它基於針對一個問 題的目標函式,計算其可能值的邊界。回溯法並不受這種要求的制約,但在大多數情況下,它處理的是非優化問題。回溯法和分支限界法的另一個區別在於它們生成 狀態空間樹的節點順序不同。對於回溯法來說,它的樹的生長順序常常是深度優先的(也就是和DFS類似)。分支限界法可以根據多種規則生成節點,如最佳優先 原則。
回溯的主要思想是每次只構造解的一個分量,然後按照下面的方法來評估這個部分構造解。如果一個部分構造解可以進一步構造而不會違反問題的約束,我們就接受 對解的下一個分量所做的第一個合法選擇。如果無法對下一分量進行合法的選擇,就不必在剩下的任何分量再做任何選擇了。在這種情況下,該演算法進行回溯,把部 分構造解的最後一個分量替換為它的下一個選擇。通過對所做的選擇構造一顆所謂的狀態空間樹,我們很容易實現這種處理。樹的根代表了在查詢解之前的初始狀 態。樹的第一層節點代表了對解的第一個分量所做的選擇,第二層節點代表了對解的第二個分量所做的選擇,以此類推。如果一個部分構造解仍然有可能導致一個完 整解,我們說這個部分解在樹中的相應節點是有希望的;否則,我們說它是沒希望的。葉子則要麼代表了沒希望的死衚衕,要麼代表了演算法找到的完整解。在大多數 情況下,一個回溯演算法的狀態空間樹是按照深度優先的方式來構造的。如果當前節點是有希望的,通過向部分解新增下一個分量的第一個合法選擇,就生成了節點的 一個子女,而處理也會轉向這個子女節點。如果當前節點變得沒希望了,該演算法回溯到該節點的父母,考慮部分解的最後一個分量的下一個可能選擇;如果這種選擇 不存在,它再回溯到樹的上一層,以此類推。最後,如果該演算法找到了問題的一個完整解,它要麼就停止了(如果只需要一個解),要麼回溯之後繼續查詢其他可能 的解。 和回溯法相比,分支限界法需要兩個額外的條件:
  • 對於一顆狀態空間樹的每一個節點所代表的部分解,我們要提供一種方法,計算出通過這個部分解繁衍出的任何解在目標函式上的最佳值邊界。
  • 目前求得的最佳解的值。


如果可以得到這些資訊,我們可以拿某個節點的邊界值和目前求得的最佳解進行比較:如果邊界值不能超越(也就是說,在最小化問題中不小於,在最大化問題中不 大於)目前的最佳解,這個節點就是一個沒有希望的節點,需要立即中止(也有人說把樹枝剪掉),因為從這個節點生成的解,沒有一個能比目前已經得到的解更 好。這就是分支限界技術的主要思想。
一般來說,對於一個分支限界演算法的狀態空間樹來說,只要符合下面三種中的一種原因,我們就會中止掉它的在當前節點上的查詢路徑:

  • 該節點的邊界值不能超越目前最佳解的值。
  • 該節點無法代表任何可行解,因為它已經違反了問題的約束。
  • 該節點代表的可行解的子集只包含一個單獨的點(因此無法給出更多的選擇)。在這種情況下,我們拿這個可行解在目標函式上的值和目前求得的最佳解進行比較,如果新的解更好一些的話,就用前者替換後者。
一些應用案例: 最近鄰居是一種簡單的貪婪演算法,用來對旅行商問題近似求解。該演算法的效能比是沒有上界的,哪怕對一種重要的子集——歐幾里德圖來說,也是如此。
饒樹兩週也是旅行商問題的一種近似演算法,對於歐幾里德圖來說,它的效能比是2。該演算法的基本思想是在圍繞最小生成樹散步的時候走捷徑。
揹包問題有一種巧妙貪婪演算法,它的基本思想是,按照價值重量比的降序處理輸入物品。對於該問題的連續版本來說,該演算法總能生成一個精確的最優解。
揹包問題的多項式近似方案是一種引數可調的多項式時間演算法,可以按照預定義的任意精度生成近似解。
解非線性方程是數值分析中最重要的領域之一。雖然我們沒有非線性方程的求根公式(只有少數例外),但有若干演算法可以對它們近似求解。
平方法和試位法分別是連續版本的折半查詢和插值查詢。它們的主要優勢在於,演算法在每次迭代時,都會把根括在某個區間裡。
牛頓法會生成近似根的一個序列,它們都是函式影象的切線在x軸上的截距。如果選擇了一個較好的初始近似值,該演算法一般只需要很少的幾次迭代,就能給出方程根的一個高精度近似值。 來源:百度空間