动态规划基本问题
http://www.cnblogs.com/chinazhangjie/archive/2010/11/16/1878400.html
動態規劃
動態規劃?
算法總體思想?
動態規劃算法與分治法類似,其基本思想也是將待求解問題分解成若干個子問題。
但是經分解得到的子問題往往不是互相獨立的。不同子問題的數目常常只有多項式量級。在用分治法求解時,有些子問題被重復計算了許多次。
如果能夠保存已解決的子問題的答案,而在需要時再找出已求得的答案,就可以避免大量重復計算,從而得到多項式時間算法。
動態規劃基本步驟:
(1)找出最優解的性質,并刻劃其結構特征。
(2)遞歸地定義最優值。
(3)以自底向上的方式計算出最優值。
(4)根據計算最優值時得到的信息,構造最優解。
實例一、完全加括號的矩陣連乘積?
問題可遞歸定義:?
(1)單個矩陣是完全加括號的;
(2)矩陣連乘積A是完全加括號的 ,則A可表示為2個完全加括號的矩陣連乘積B和C的乘積并加括號,即 A = (BC)。
設有四個矩陣A,B,C,D它們的維數分別是: A = 50*10 , B = 10*40 , C = 40*30 , D = 30*5
總共有五中完全加括號的方式:
?
例如:((A(BC))D): 10 * 40 * 30 + 10 * 30 * 50 + 50 * 30 * 5 = 34500
??? 給定矩陣{A1, A2, A3,..., An},其中Ai與A(i+1)是可乘的。i = 1,2,3, ..., n - 1。考察這n個矩陣的連乘積A1*A2*A3...An.
由于矩陣乘法滿足結合律,所以計算矩陣的連乘可以有許多不同的計算次序。這種計算次序可以用加括號的方式來確定。
若一個矩陣連乘積的計算次序完全確定,也就是說該連乘積已完全加括號,則可以依此次序反復調用2個矩陣相乘的標準算法計算出矩陣連乘積。
矩陣連乘問題?
??? 給定矩陣{A1, A2, A3,..., An},其中Ai與A(i+1)是可乘的。i = 1,2,3, ..., n - 1。考察這n個矩陣的連乘積A1*A2*A3...An. 如何確定計算矩陣連乘積的計算次序,使得依此次序計算矩陣連乘積需要的數乘次數最少.
窮舉法:列舉出所有可能的計算次序,并計算出每一種計算次序相應需要的數乘次數,從中找出一種數乘次數最少的計算次序。
算法復雜度分析:
對于n個矩陣的連乘積,設其不同的計算次序為P(n)
由于每種加括號方式都可以分解為兩個子矩陣的加括號問題
(A1...Ak)(A(k+1)…An)可以得到關于P(n)的遞推式如下:
動態規劃:將矩陣連乘積A(i)A(i+1)…A(j)簡記為A[i:j],這里 i <= j。
考察計算A[i:j]的最優計算次序。設這個計算次序在矩陣A(k)和A(k+1)之間將矩陣鏈斷開,i <= k < j, 則其相應完全加括號方式為(A(i)A(i+1)...A(k)) * (A(k+1)A(k+2)...A(j))。
計算量:A[i:k]的計算量加上A[k+1,j],再加上A[i:k] * A[k+1][j]的計算量。
分析最優解的結構?
特征:計算A[i:j]的最優次序所包含的計算矩陣子鏈 A[i:k]和A[k+1:j]的次序也是最優的。
矩陣連乘計算次序問題的最優解包含著其子問題的最優解。這種性質稱為最優子結構性質。問題的最優子結構性質是該問題可用動態規劃算法求解的顯著特征。
建立遞歸關系?
設計算A[i:j],1 <= i <= j <= n,所需要的最少數乘次數m[i,j],則原問題的最優值為m[1,n]
當i = j時,A[i:j]=Ai,因此,m[i,i] = 0,i = 1,2,…,n
當i < j時,m[i,j] = m[i,k] + m[k+1,j] + p(i-1)p(k)p(j)
這里A(i)的維數為p(i-1)*(i)(注:p(i-1)為矩陣A(i)的行數,p(i)為矩陣A[i]的列數)
可以遞歸地定義m[i,j]為:
k的位置只有j - i種。
計算最優值?
對于1 <= i <= j <= n不同的有序對(i,j)對應于不同的子問題。因此,不同子問題的個數最多只有:
(大括號表示C(n,2),組合的意思。后面的符號表示 “緊漸近界記號”)
但是,在遞歸計算時,許多子問題被重復計算多次。這也是該問題可用動態規劃算法求解的又一顯著特征。
用動態規劃算法解此問題,可依據其遞歸式以自底向上的方式進行計算。在計算過程中,保存已解決的子問題答案。每個子問題只計算一次,而在后面需要時只要簡單查一下,從而避免大量的重復計算,最終得到多項式時間的算法。
用動態規劃法求最優解?
連乘矩陣假如為:
計算過程為:
從m可知最小連乘次數為m[1][6] = 15125
從s可知計算順序為((A1(A2A3))((A4A5))A6))
實現:
?
代碼?
?
算法復雜度分析:?
算法matrixChain的主要計算量取決于算法中對r,i和k的3重循環。循環體內的計算量為O(1),而3重循環的總次數為O(n^3)。因此算法的計算時間上界為O(n^3)。算法所占用的空間顯然為O(n^2)。
動態規劃算法的基本要素?
一、最優子結構?
矩陣連乘計算次序問題的最優解包含著其子問題的最優解。這種性質稱為最優子結構性質。
在分析問題的最優子結構性質時,所用的方法具有普遍性:首先假設由問題的最優解導出的子問題的解不是最優的,然后再設法說明在這個假設下可構造出比原問題最優解更好的解,從而導致矛盾。
利用問題的最優子結構性質,以自底向上的方式遞歸地從子問題的最優解逐步構造出整個問題的最優解。最優子結構是問題能用動態規劃算法求解的前提。
同一個問題可以有多種方式刻劃它的最優子結構,有些表示方法的求解速度更快(空間占用小,問題的維度低)
二、重疊子問題
?遞歸算法求解問題時,每次產生的子問題并不總是新問題,有些子問題被反復計算多次。這種性質稱為子問題的重疊性質。
?動態規劃算法,對每一個子問題只解一次,而后將其解保存在一個表格中,當再次需要解此子問題時,只是簡單地用常數時間查看一下結果。
通常不同的子問題個數隨問題的大小呈多項式增長。因此用動態規劃算法只需要多項式時間,從而獲得較高的解題效率。
三、備忘錄方法
備忘錄方法的控制結構與直接遞歸方法的控制結構相同,區別在于備忘錄方法為每個解過的子問題建立了備忘錄以備需要時查看,避免了相同子問題的重復求解。
實現(見矩陣連乘源碼)
實例二、最長公共子序列?
??? 若給定的序列X = {x1,x2,…,xm},則另一序列Z = {z1,z2,…,zk},是X的子序列是指存在一個嚴格下表序列{i1,i2,…,ik}使得對于所有的j = 1,2,…k有zj = xij。例如,序列Z = {B,C,D,B}是序列X = {A,B,C,B,D,A,B}的子序列,相應的遞增下標序列為{2,3,5,7}。
給定2個序列X和Y,當另一序列Z既是X的子序列又是Y的子序列時,稱Z是序列X和Y的公共子序列。
問題表述:給定2個序列X={x1,x2,…,xm}和Y = {y1,y2,…,yn},找出X和Y的最長公共子序列。
最長公共子序列的結構?
設序列X = {x1,x2,…,xm}和Y = {y1,y2,…,yn}的最長公共子序列為Z = {z1,z2,…,zk} ,則
(1)若xm = yn,則zk = xm = yn,且z(k-1)是x(m-1)和y(n-1)的最長公共子序列。
(2)若xm != yn且zk != xm,則Z是x(m-1)和Y的最長公共子序列。
(3)若xm != yn且zk != yn,則Z是X和y(n-1)的最長公共子序列。
由此可見,2個序列的最長公共子序列包含了這2個序列的前綴的最長公共子序列。因此,最長公共子序列問題具有最優子結構性質。
子問題的遞歸結構?
由最長公共子序列問題的最優子結構性質建立子問題最優值的遞歸關系。用c[i][j]記錄序列Xi和Yi的最長公共子序列的長度。其中, Xi={x1,x2,…,xi};Yj={y1,y2,…,yj}。當i = 0或j = 0時,空序列是Xi和Yj的最長公共子序列。故此時C[i][j] = 0。其它情況下,由最優子結構性質可建立遞歸關系如下:
由于在所考慮的子問題空間中,總共有θ(mn)個不同的子問題,因此,用動態規劃算法自底向上地計算最優值能提高算法的效率
計算最優值和構造最長公共子序列(見源碼)?
實現:?
? 代碼?
?
算法的改進
在算法lcsLength和lcs中,可進一步將數組b省去。事實上,數組元素c[i][j]的值僅由c[i-1][j-1],c[i-1][j]和c[i][j-1]這3個數組元素的值所確定。對于給定的數組元素c[i][j],可以不借助于數組b而僅借助于c本身在時間內確定c[i][j]的值是由c[i-1][j-1],c[i-1][j]和c[i][j-1]中哪一個值所確定的。
如果只需要計算最長公共子序列的長度,則算法的空間需求可大大減少。事實上,在計算c[i][j]時,只用到數組c的第i行和第i-1行。因此,用2行的數組空間就可以計算出最長公共子序列的長度。進一步的分析還可將空間需求減至O(min(m,n))。
實例三、最大子段和?
問題表述?
n個數(可能是負數)組成的序列a1,a2,…an.求該序列
例如:? 序列(-2,11,-4,13,-5,-2) ,最大子段和:
?????? 11 - 4 + 13=20。
(1)窮舉算法: O(n3), O(n2)
(2)分治法:
將序列a[1:n]從n/2處截成兩段:a[1:n/2], a[n/2+1:n]
實例三、最大子段和
問題表述
n個數(可能是負數)組成的序列a1,a2,…an.求該序列?子序列的最大值。
也就是
?
例如:? 序列(-2,11,-4,13,-5,-2) ,最大子段和:
?????11 - 4 + 13=20。
(1)窮舉算法: O(n3), O(n2)
(2)分治法:
將序列a[1:n]從n/2處截成兩段:a[1:n/2], a[n/2+1:n]
一共存在三種情況:
a.最大子段和出現在左邊一段
b.最大子段和出現在右邊一段
c.最大子段和跨越中間的斷點
對于前兩種情況,只需繼續遞歸調用,而對于第三種情況:
那么S1+S2是第三種情況的最優值。
(3)動態規劃法:
定義b[j]:
含義:從元素i開始,到元素j為止的所有的元素構成的子段有多個,這些子段中的子段和最大的那個。
那么:
如果:b[j-1] > 0, 那么b[j] = b[j-1] + a[j]
如果:b[j-1] <= 0,那么b[j] = a[j]
這樣,顯然,我們要求的最大子段和,是b[j]數組中最大的那個元素。
實現:
? 代碼?
?
實例四、多邊形游戲
多邊形游戲是一個單人玩的游戲,開始時有一個由n個頂點構成的多邊形。每個頂點被賦予一個整數值,每條邊被賦予一個運算符”+”或”*”。所有邊依次用整數從1到n編號。
游戲第1步,將一條邊刪除。
隨后n-1步按以下方式操作:
(1)選擇一條邊E以及由E連接著的2個頂點V1和V2;
(2)用一個新的頂點取代邊E以及由E連接著的2個頂點V1和V2。將由頂點V1和V2的整數值通過邊E上的運算得到的結果賦予新頂點。
最后,所有邊都被刪除,游戲結束。游戲的得分就是所剩頂點上的整數值。
問題:?對于給定的多邊形,計算最高得分。
最優子結構性質
按照順時針順序,多邊形和頂點的順序可以寫成:
????op[1], v[1], op[2], v[2],?…, op[n], v[n]
在所給多邊形中,從頂點i(1 <= i <= n)開始,長度為j(鏈中有j個頂點)的順時針鏈p(i,j)?可表示為
v[i], op[i+1], v[i+1],…, op[i+j-1], v[i+j-1]
如果這條鏈在op[i + s]處進行最后一次合并運算(1 <= s <= j-1),則可在op[i+s]處將鏈分割為2個子鏈:
從i開始長度為s的鏈:??p(i,s)
從i + s開始,長度為j - s的鏈:p(i + s,j-s)。
設:
m1是對子鏈p(i,s)的任意一種合并方式得到的值,而a和b分別是在所有可能的合并中得到的最小值和最大值。
m2是p(i+s,j-s)的任意一種合并方式得到的值,而c和d分別是在所有可能的合并中得到的最小值和最大值。
依此定義有a <= m1 <= b,c <= m2 <= d
(1)當op[i+s] = ‘+’時,顯然有a + c <= m <= b + d
(2)當op[i+s] = ’*’時,有
min {ac,ad,bc,bd} <= m <= max {ac,ad,bc,bd}
換句話說,主鏈的最大值和最小值可由子鏈的最大值和最小值得到。
實現:
代碼?
分類:?Data structure and Algorithm總結
- 上一篇: (int)a和(int)a的区别
- 下一篇: 卡特兰