天天看點

分治、動态規劃、貪心、回溯、分支限界算法

分治法

把一個複雜的問題分成兩個或更多的相同或相似的子問題,再把子問題分成更小的子問題……直到最後子問題可以簡單的直接求解,原問題的解即子問題的解的合并(子問題須互相獨立,且與原問題形式相同)。

設計思想:

将一個難以直接解決的大問題,分割成一些規模較小的相同問題,以便各個擊破,分而治之。

分治政策:算法設計政策叫做分治法

、對于一個規模為n的問題,若該問題可以容易地解決(比如說規模n較小)則直接解決,否則将其分解為k個規模較小的子問題,這些子問題互相獨立且與原問題形式相同,遞歸地解這些子問題,然後将各子問題的解合并得到原問題的解。

分治法适用的情況

分治法所能解決的問題一般具有以下幾個特征:

1、該問題的規模縮小到一定的程度就可以容易地解決

2、該問題可以分解為若幹個規模較小的相同問題,即該問題具有最優子結構性質。

3、利用該問題分解出的子問題的解可以合并為該問題的解(不滿足該條件,可考慮用貪心法或動态規劃法);

4、該問題所分解出的各個子問題是互相獨立的,即子問題之間不包含公共的子子問題。

分治法的基本步驟

分解:将原問題分解為若幹個規模較小,互相獨立,與原問題形式相同的子問題;

解決:若子問題規模較小而容易被解決則直接解,否則遞歸地解各個子問題

合并:将各個子問題的解合并為原問題的解。

一般的算法設計模式:

Divide-and-Conquer(P)

1、if |P|≤n0 then return(ADHOC(P)) // 當P的規模不超過n0時直接用算法ADHOC(P)求解

2、将P分解為較小的子問題 P1 ,P2 ,…,Pk

3、遞歸解各子問題Pi

for i←1 to k

do yi ← Divide-and-Conquer(Pi)

4、合并各子問題解,得到問題P的最終解

T ← MERGE(y1,y2,…,yk)

return(T)

說明:

P: 表示問題

|P|:表示問題P的規模

n0: 為一門檻值,表示當問題P的規模不超過n0時,問題已容易直接解出,不必再繼續分解。

ADHOC(P):分治法中的基本子算法,用于直接解小規模的問題P。

分治法類似于數學歸納法,找到解決本問題的求解方程公式,然後根據方程公式設計遞歸程式:

1、先找到最小問題規模時的求解方法

2、然後考慮随問題規模增大時的求解方法

3、找到求解的遞歸函數式後(各種規模或因子),設計遞歸程式。

分治法的複雜性分析

一個分治法将規模為n的問題分成k個規模為n/m的子問題去解。設分解閥值n0=1,且adhoc解規模為1的問題耗費1個機關時間。再設将原問題分解為k個子問題以及用merge将k個子問題的解合并為原問題的解需用f(n)個機關時間。用T(n)表示該分治法解規模為|P|=n的問題所需的計算時間,則有:

T(n)= k T(n/m)+f(n)
           

通過疊代法求得方程的解:

遞歸方程及其解隻給出n等于m的方幂時T(n)的值,但是如果認為T(n)足夠平滑,那麼由n等于m的方幂時T(n)的值可以估計T(n)的增長速度。通常假定T(n)是單調上升的,當

mi≤n<mi+1

時,

T(mi)≤T(n)<T(mi+1)

分治法求解的一些經典問題

二分搜尋

大整數乘法

Strassen矩陣乘法

棋盤覆寫

合并排序

快速排序

傅立葉變換(快速傅立葉變換)

線性時間選擇

最接近點對問題

循環賽日程表

漢諾塔

動态劃分算法

動态規劃所處理的問題是一個多階段決策問題,一般由初始狀态開始,通過對中間階段決策的選擇,達到結束狀态。這些決策形成了一個決策序列,同時确定了完成整個過程的一條活動路線(通常是求最優的活動路線)

每次決策依賴于目前狀态,又随即引起狀态的轉移。

一個決策序列就是在變化的狀态中産生出來的,

是以,這種多階段最優化決策解決問題的過程就稱為動态規劃。

基本思想、政策

基本思想與分治法類似,也是将待求解的問題分解為若幹個子問題(階段),按順序求解子階段,前一子問題的解,為後一子問題的求解提供了有用的資訊。在求解任一子問題時,列出各種可能的局部解,通過決策保留那些有可能達到最優的局部解,丢棄其他局部解。依次解決各子問題,最後一個子問題就是初始問題的解。

由于動态規劃解決的問題多數有重疊子問題(分解後得到的子問題往往不是互相獨立的—即下一子階段的求解是建立在上一個子階段的解的基礎上,進行進一步的求解,且有重疊子問題)這個特點,為減少重複計算,對每一個子問題隻解一次,将其不同階段的不同狀态儲存在一個二維數組中。

動态規劃求解的問題的一般要具有3個特性:

1、問題具有最優子結構,即滿足最優化原理。

2、無後效性:即某階段狀态一旦确定,就不受這個狀态以後決策的影響(某狀态以後的過程不會影響以前的狀态,隻與目前狀态有關)。

3、有重疊子問題:即子問題之間是不獨立的,一個子問題在下一階段決策中可能被多次使用到。

動态規劃求解的基本步驟:

初始狀态→│決策1│→│決策2│→…→│決策n│→結束狀态

1、劃分階段:

按照問題的時間或空間特征,把問題分為若幹個階段。注意劃分後的階段一定要是有序的或者是可排序的,否則問題就無法求解。

2、确定狀态和狀态變量:

将問題發展到各個階段時所處于的各種客觀情況用不同的狀态表示出來,且狀态的選擇要滿足無後效性。

3、确定決策、狀态轉移方程:

因為決策和狀态轉移有着天然的聯系,狀态轉移就是根據上一階段的狀态和決策來導出本階段的狀态。是以如果确定了決策,狀态轉移方程也就可寫出。但事實上常常是反過來做,根據相鄰兩個階段的狀态之間的關系來确定決策方法和狀态轉移方程。

4、尋找邊界條件:

給出的狀态轉移方程是一個遞推式,需要一個遞推的終止條件或邊界條件。

一般,隻要解決問題的階段、狀态和狀态轉移決策确定了,就可以寫出狀态轉移方程(包括邊界條件)

實際算法實作的設計步驟:

1、分析最優解的性質,并刻畫其結構特征。

2、遞歸的定義最優解。

3、以自底向上或自頂向下的記憶化方式(備忘錄法)計算出最優值

4、根據計算最優值時得到的資訊,構造問題的最優解

算法實作的說明

動态規劃求解問題,最重要的就是确定動态規劃三要素:

1、問題的階段

2、每個階段的狀态

3、從前一個階段轉化到後一個階段之間的遞推關系。

遞推關系必須是從次小的問題開始到較大的問題之間的轉化,動态規劃往往可以用遞歸程式來實作,遞推可以充分利用前面儲存的子問題的解來減少重複計算(動态規劃算法的核心之處)。

确定了動态規劃的這三要素,整個求解過程就可以用一個最優決策表來描述,最優決策表是一個二維表:

1、行表示決策的階段

2、清單示問題狀态,表格需要填寫的資料一般對應此問題的在某個階段某個狀态下的最優值(如最短路徑,最長公共子序列,最大價值等)

3、填表的過程就是根據遞推關系,從1行1列開始,以行或者列優先的順序,依次填寫表格,

最後根據整個表格的資料通過簡單的取舍或者運算求得問題的最優解。

f(n,m)=max{f(n-1,m), f(n-1,m-w[n])+P(n,m)}

動态規劃算法基本架構

複制代碼

代碼

for(j=1; j<=m; j=j+1) // 第一個階段

xn[j] = 初始值;

for(i=n-1; i>=1; i=i-1)// 其他n-1個階段

for(j=1; j>=f(i); j=j+1)// f(i)與i有關的表達式

//通過決策保留那些有可能達到最優的局部解,丢棄其他局部解

xi[j] = max(或min){g(xi-1[j1:j2]), ……, g(xi-1[jk:jk+1])};

t = g(x1[j1:j2]); // 由子問題的最優解求解整個問題的最優解的方案

貪心算法

在對問題求解時,總是做出在目前看來是最好的選擇(不從整體最優上加以考慮,僅是在某種意義上的局部最優解)

貪心算法沒有固定的算法架構,算法設計的關鍵是貪心政策的選擇。必須注意的是,貪心算法不是對所有問題都能得到整體最優解,選擇的貪心政策必須具備無後效性

無後效性:即某個狀态以後的過程不會影響以前的狀态,隻與目前狀态有關。

貪心政策适用的前提是:

用貪心算法隻能通過解局部最優解的政策來達到全局最優解,要注意判斷問題是否适合采用貪心算法政策,找到的解是否一定是問題的最優解,對一個問題分析是否适用于貪心算法,可以先選擇該問題下的幾個實際資料進行分析,就可做出判斷

貪心算法的基本思路:

1、建立數學模型來描述問題。

2、把求解的問題分成若幹個子問題。

3、對每一子問題求解,得到子問題的局部最優解。

4、把子問題的解局部最優解合成原來解問題的一個解。

貪心算法的實作架構

從問題的某一初始解出發;

while (能朝給定總目标前進一步){

利用可行的決策,求出可行解的一個解元素;

}

由所有解元素組合成問題的一個可行解;

回溯法:選優搜尋法(深度優先搜尋),在解空間樹中回溯尋找所有解

基本思想

回溯法深度優先搜尋解空間樹中活結點的所有可行子結點被周遊後才被從棧中彈出找出滿足限制條件的所有解

回溯法是一種選優搜尋法,按選優條件向前搜尋,以達到目标。但當探索到某一步時,發現原先選擇并不優或達不到目标,就退回一步重新選擇,這種走不通就退回再走的技術為回溯法,而滿足回溯條件的某個狀态的點稱為“回溯點”。

回溯法的搜尋政策

在包含問題的所有解的解空間樹中,按照深度優先搜尋的政策,從根結點出發深度探索解空間樹。當探索到某一結點時,要先判斷該結點是否包含問題的解,如果包含,就從該結點出發繼續探索下去,如果該結點不包含問題的解,則逐層向其祖先結點回溯。

1、若用回溯法求問題的所有解時:要回溯到根,且根結點的所有可行的子樹都要已被搜尋遍才結束。

2、而若使用回溯法求任一個解時:隻要搜尋到問題的一個解就可以結束。

回溯法一般步驟:

1、确定問題的解空間:

首先應明确定義問題的解空間,問題的解空間應至少包含問題的一個(最優)解。

2、确定結點的擴充搜尋規則

3、以深度優先方式搜尋解空間,并在搜尋過程中用剪枝函數避免無效搜尋。

分支限界法:廣度優先政策或者最小耗費(最大效益)優先,搜尋一個解或者最優解

分支限界法的求解目标是找出滿足限制條件的一個解,或是在滿足限制條件的解中找出使某一目标函數值達到極大或極小的解,即在某種意義下的最優

分支限界法以廣度優先或最小消耗優先搜尋解空間樹、解空間樹每個結點隻有一次成為活結點的機會找出滿足限制條件的一個解或特定意義下的最優解

分支搜尋算法

所謂“分支”就是采用廣度優先的政策,依次搜尋E-結點的所有分支,也就是所有相鄰結點,抛棄不滿足限制條件的結點,其餘結點加入活結點表。然後從表中選擇一個結點作為下一個E-結點,繼續搜尋。

選擇下一個E-結點的方式不同,則會有幾種不同的分支搜尋方式。

1、FIFO搜尋

2、LIFO搜尋

3、優先隊列式搜尋

分支限界法的搜尋政策:

分支限界法常以廣度優先或以最小耗費(最大效益)優先的方式搜尋問題的解空間樹。問題的解空間樹是表示問題解空間的一棵有序樹,常見的有子集樹和排列樹。

在擴充結點處,先生成其所有的兒子結點(分支),然後再從目前的活結點表中選擇下一個擴充對點。為了有效地選擇下一擴充結點,以加速搜尋的程序,在每一活結點處(每一個活結點隻有一次機會成為擴充結點。活結點一旦成為擴充結點,就一次性産生其所有兒子結點。在這些兒子結點中,那些導緻不可行解或導緻非最優解的兒子結點被舍棄,其餘兒子結點被子加入活結點表中),計算一個函數值(限界),并根據這些已計算出的函數值,從目前活結點表中選擇一個最有利的結點作為擴充結點,使搜尋朝着解空間樹上有最優解的分支推進,以便盡快地找出一個最優解

回溯法和分支限界法的一些差別:

1、方法對解空間樹的搜尋方式:

回溯法以深度優先的方式搜尋解空間樹T, 分支限界法則以廣度優先或以最小耗費優先的方式搜尋解空間樹T

2、存儲結點的常用資料結構

3、結點存儲特性

繼續閱讀