動態規劃的狀態表示

                                        中國科技大學計算機系----黃浩達

一、引言
  問題求解技術,包括兩個方面的內容:表示和搜索。在這兩個方面的內容中,
搜索是重點,表示是基礎。不同的狀態表示對搜索的效率會產生極大的影響。一個
粗糙的狀態表示可能使得搜索時要對狀態變換進行更多的操作,而採取簡潔的表示
,搜索時進行的操作可能就顯得方便、高效,甚至由於狀態表示準確描述了問題的
本質,給人以啓示,從而找到更好的搜索技術。動態規劃是求解問題的一個重要技
術,它的狀態表示在整個算法中有着舉足輕重的作用,對整個算法的影響也遠比其
他搜索技術中的狀態表示更爲深刻。
本文以實例對動態規劃的狀態表示進行一些討論。

二、 動態規劃對狀態表示的要求
  在動態規劃程序設計中,我們主要利用了問題的兩個性質:最優子結構和子問
題重疊。最優子結構指問題的最優解包含了子問題的最優解,它是動態規劃方法可
行的理論基礎。而一個問題具有子問題重疊性質是指用遞歸算法自頂向下解這個問
題時,並不總是產生新的子問題,有些子問題被重複求解多次。
  因爲最優子結構性質,動態規劃求問題最優解時,可以轉化爲求子問題的最優
解,而對解決過的問題,動態規劃則記錄它的結果,當再次遇上已解決的問題,就
可以直接利用結果。子問題重疊性質保證了這樣做是有意義的。但一般的搜索技術
,對於某個子問題不管是否已經解決過,只要遇上,就會再次對這個子問題進行求
解。
  很明顯,動態規劃與一般搜索技術最大不同的地方就是記錄了已求解過的問題
的結果。這裏包含了兩個方面的內容 :子問題的記錄和子問題結果的記錄。其中
,子問題的記錄是最重要,也是最爲複雜的,它就是通常我們所說的狀態表示。
通常我們用一個數、一組數或一個向量來實現狀態表示。但無論採取什麼方法,從
動態規劃的原理來看,狀態表示要滿足兩個要求:正確、合理描述子問題和描述的
子問題滿足最優子結構性質;從算法實現角度來看,狀態表示必須能夠用基本數據
結構實現並且能滿足空間要求。
下面通過兩個問題來闡述動態規劃對狀態表示的要求。

問題一:存在一個數字三角形,從頂到底有多條路徑, 每一步可沿左斜線向下或
沿右斜線向下。路徑所經過的數字之和稱爲路徑得分,要求求出最小路徑得分。
例: 
      1 1 
    2 3 2 3 
  3 2 3 3 2 3  
3 8 1 2 3 8 1 2 
最小路徑得分=6 
狀態表示1-1 
最自然的作法是用一元組(X)描述問題,D(X)表示從頂到達第X層的得分。但是
一元組(X)描述的子問題不能滿足最優子結構性質, 因爲D(X)的最優解可能不
包含子問題D(X-I)的最優解。這樣,動態規劃方法是無法在狀態表示1-1上應用
的。
狀態表示 1-2
用二元組D(X,Y)描述問題,D(X,Y)表示到達第X層第Y個位置時的得分,那麼
D(X,Y)的最優解包含了子問題D(X-1,Y)或D(X-1,Y-1)的最優解,狀態轉
移方程爲
D(X,Y)= Max {D(X-1,Y),D(X-1,Y-1)} + A[X,Y]
D(1,1)= A[1,1]
這樣,最小路徑得分可以通過比較底層的分數求得。
一般情況下,我們找到的狀態表示應能刻劃子問題的特徵,困難的是如何找到描述
的子問題能滿足最優子結構性質的狀態表示,而這一點恰恰是決定該問題能否應用
動態規劃方法的重要因素。狀態表示1-1描述的問題是正確的,但它不能滿足最優
子結構性質,使得無法用它來建立動態規劃數學模型。狀態分析的過程實際上是分
析問題最優子結構的過程,不同的狀態表示正是從不同的角度去試圖刻劃問題的最
優子結構。只有狀態表示描述的子問題能滿足最優子結構性質,我們才能在此基礎
上正確的建立起動態規劃數學模型。

問題二 : 在茫茫大海中,有一座荒蕪人煙的小島,它有着肥沃的土地,終年四季
如春。在許多年的沉寂後,移民者終於踏上了這塊土地,接下來的事情就是對土地
進行墾荒。小島呈不規則多邊形形狀,爲了便於管理,移民者決定將小島劃分爲三
角形區域且三角形區域的個數要最少,這些三角形區域的頂點必須是小島的頂點。
 顯然, 用來描述小島的多邊形的任兩個頂點不重合,任兩條邊不相交,三角形區
域內只有陸地。
要求輸入多邊形的頂點數 n和它的順時針座標,返回最小區域數和具體的劃分方法

例 : 給定如左圖所示的小島, 可有右圖所示的兩種劃分, (1)劃分爲3個區域
,是最優的。(2)劃分爲4個區域。

圖(1) 圖(2)
狀態表示2-1
根據多邊形的自然特徵,一個多邊形頂點的順時針序列將正確的描述多邊形的特徵
。例如在圖(1)中,序列(1,2, …,N-1 ,N)可以表示多邊形A,序列(1,2,
…,K)可以表示多邊形B,同樣序列(K,K+1,…,N)可以表示多邊形C。
由於在問題二中,多邊形的頂點的序號已經隱含了頂點之間的順序,我們只要記錄
多邊形的頂點,而不必記錄頂點順序。基於這個性質,我們可以用一個十進制數來
表示一種狀態。一個十進制數通過它對應的二進制數來描述多邊形。二進制數X第
k位上的0、1值代表這個多邊形是否包含第k個頂點。例如 (011011)2的1,2,4
,5位上數值是1,則 這個二進制數代表多邊形(1,2,4,5),用相應的十進制
數表示就是27。
於是用一元組(A)描述多邊形, D(A)表示多邊形A的劃分區域數。多邊形B、C
是由多邊形劃分A而成的兩個多邊形,那麼,這種劃分下,多邊形的最優劃分必然
包含多邊形B、C的最優劃分,問題滿足最優子結構性質。
那麼狀態轉移方程可以表示爲
D(A)= Min(D(B)+ D(C))
子問題的空間複雜度爲O(2n),當n=20,基本堆空間就溢出了(本文假設基本堆空間
是219=524288 byte並且每個子問題的狀態表示只要1 byte) ,動態規劃只能處理
頂點數小於20的多邊形。
狀態表示2-2
定義2-2 多邊形(A1,A2,…,Ak)是由多邊形(1,2,…,N)劃分而來的多邊形,
我們稱多邊形(A1,A2,…,Ak)爲半連續多邊形,當且僅當Ai+1 = Ai+1 ,
k>i >1。圖4中多邊形(1,4,5,6,7)就是一個半連續多邊形。
性質2-2 對於一個多邊形,它的任一頂點a只有兩種劃分情況:一是頂點a的兩個相
鄰頂點連接,一是頂點a與其他頂點連接,並且這兩種劃分必有其一。如圖3,頂點
1的劃分情況:頂點1的相鄰頂點(2,9)連接;頂點1與頂點4連接。

我們可以用一個三元組(X,Y,Z)描述半連續多邊形,D(X,Y,Z)表示半連續多邊形(
X,Y,Y+1,…,Z)的劃分區域數。
根據性質2-1,對半連續多邊形(X, Y, Z)可以只考慮頂點X 的劃分,劃分後的多
邊形仍然是半連續多邊形,於是,狀態表示2-2不但可以描述問題的特徵,也可以
正確描述子問題的特徵。考慮到(X,Y,Z)最優劃分包含了它的子半連續多邊形
的最優劃分,狀態表示2-2描述的子問題滿足最優子結構性質。
根據定義,初始多邊形是一個半連續多邊形,表示爲(1,2,N)。狀態轉移方程

D(X,Y,Z) = Min {D(Y,Y+1,Z)+g(X,Y,Z), D(X,J,Z)+D(X,Y,J)}, Z<J<Y
f(J,I,I) = 0, n+1>I>J>0,
當X,Y,Z在一條直線時,g(X,Y,Z) = 0, 否則g(X,Y,Z) = 1。
狀態表示2-2的子問題空間只有 O(n3),動態規劃最多可以處理頂點數 80的多邊形
。以下給出求半連續多邊形最優劃分區域數的函數。
[算法2-2]:
function Dynamic(x, y, z : integer) : integer; 
{求半連續多邊形(x,y, z)的最優劃分}
var j, tot : integer;
begin
  if D[x, y, z] = 255 then
  if y - z = 1 then 
  if x,y,z三點共線 then D[x, y, z] := 0 
                   else D[x,y,z] := 1
else
begin
  if 頂點y與頂點z連接合法 then
  begin
    D[x,y,z] := Dynamic(y,y+1,z);
    If x,y,z 三點不共線 then D[x,y,z] := D[x,y,z]+1;
  End; 
  for j := y + 1 to z - 1 do {j 是頂點x要連接的頂點}
    if 頂點x與頂點j 連接合法then
    begin
      Tot := Dynamic(x, y, j) + Dynamic(x, j, z); 
      {子多邊形的最優劃分}
      if Tot < D[x, y, z] then 
      begin
        D[x, y, z] := Tot;
      end;
    end;
  end;
  Dynamic := D[x, y, z];
end;

  上述兩種狀態表示都能正確描述多邊形,並且描述的多邊形都能滿足最優子結
構性質,從動態規劃原理要求來看,已經滿足要求了,在狀態表示2-1、狀態表示
2-2基礎上可以正確的建立動態規劃數學模型。但是,具體實現方面仍有一些問題
沒有解決。

  從圖中可以看到,狀態表示2-1的空間要求隨着頂點數n的增大急劇增長,正如
前面所分析的,當n=20時,常用的堆空間就溢出了。而隨着頂點數n的增大,狀態
2-2的空間要求的增大相對就緩慢多了,n一直到81堆空間才溢出。空間方面的要求
強烈制約了的動態規劃的處理問題能力。因此,應用動態規劃時,我們採用的狀態
表示不僅要滿足動態規劃原理,還必須考慮實現狀態表示的空間要求。這兩方面體
現了對狀態表示正確性、可行性的要求,狀態表示必須滿足這兩個要求,動態規劃
算法才能實現。

三、狀態表示對動態規劃性能的影響

  我們分析問題的時候,總是從不同的角度去思考,以便能全面、本質地認識問
題。分析問題的狀態表示,我們也是儘可能從不同角度去思考。由此會得到對問題
的不同狀態表示,從動態規劃原理來看,其中有些狀態表示不能合乎要求,而在滿
足要求的那些狀態表示中,我們可以以之爲基礎,構造動態規劃模型,實現動態規
划算法。在通常情況下,基於不同的狀態表示的動態規劃算法性能存在着差異,這
主要從算法的時間複雜度和空間複雜度體現出來。
上面介紹了問題二的兩種狀態表示, 狀態表示2-1從問題的自然特徵來思考, 提
出對一般多邊形的表示方法,具有其通用性,狀態表示2-2則根據多邊形劃分中關
於頂點劃分的性質來思考,進而提出了半連續多邊形, 現在我們考慮關於多邊形
邊的劃分性質,提出狀態表示2-3, 並比較三種狀態表示,探討狀態表示對動態規
劃性能的影響。

狀態表示2-3
定義2-3 多邊形(A1,A2,…,Ak)是由多邊形(1,2,…,N)劃分而來的多邊形,
我們稱多邊形(A1,A2,…,Ak)爲連續多邊形,當且僅當Ai+1 = Ai+1 ,
k>i >0。圖6中多邊形(3,4,5,6,7)就是一個連續多邊形。
性質2-3 對於一個多邊形,它的任一條邊一定與另一個頂點組成三角形。如圖5,
邊(1,2)可以與頂點4等頂點相連,形成三角形。 
根據性質2-3, 對多邊形劃分時,我們可以按需要選擇邊來與其他頂點相連,而不
會遺漏多邊形的任一種劃分,自然也不會遺漏多邊形的最優劃分。

   連續多邊形(X,X+1,,…,Y)可以用二元組(X,Y)來表示,則D(X,Y)表示
連續多邊形的劃分區域數。
  對於連續多邊形(X,Y),只要我們選擇邊(X,Y)與頂點Z(X<Z<Y)連接,那
麼(X,Y)劃分爲三部分:連續多邊形(X,Z)、連續多邊形(Z,Y)和三角形(
X,Z,Y)。(X,Y)的最優劃分包含了(X,Z)、(Z,Y)的最優劃分,滿足最優
子結構性質。
注意到初始多邊形是一個連續多邊形,根據數學歸納法,它的子問題都是連續多邊
形。因此二元組(X,Y)是一個正確的狀態表示。狀態轉移方程爲
D(X,Y) = min(g(X,Y,Z) + D(X,Z)+D(Z,Y)), X<Z<Y,
f(i,i) = 0, n+1>i>0,
當x,y,z在一條直線時,g(x,y,z) = 0, 否則g(x,y,z) = 1。
子問題空間複雜度是O(n2),在本文的假設條件下,使用基本堆空間可以處理頂
點數700以內的多邊形。下面是求連續多邊形最優劃分區域數的函數。
[算法2-3]:
function Dynamic(s, t : integer) : integer; {求連續多邊形(s,t)的最優劃
分}
var j, tot : integer;
begin
  if D[s, t][1] = 255 then
    if t - s = 1 then D[s, t][1] := 0 
       else begin
              for j := s + 1 to t - 1 do {j 是邊(s,t)要連接的頂點}
                if 頂點j與頂點s、t連接合法 then
                begin
                  Tot := Dynamic(s, j) + Dynamic(j, t); {子多邊形的最優劃分}
                  If 頂點s、t、j不在一條直線上 then Tot := Tot + 1; 
                  if Tot < D[s, t][1] then
                  begin
                    D[s, t][1] := Tot;
                    D[s, t][2] := j; 
                  end;
                end;
            end;
  Dynamic := D[s, t][1];
end;

圖7
我們來比較三種狀態表示描述的子問題空間以及相應動態規劃算法的時空性能。在
圖7中,動態規劃的時間複雜度、空間複雜度與子問題空間增長是同階的。事實上
,這樣的關係不僅僅侷限於這個例子,它具有普遍意義。首先,動態規劃空間花費
主要是用來存儲描述子問題的狀態表示,因此空間複雜度自然隨着子問題的增多而
增大。其次,動態規劃的時間花費主要取決於要解決的不同子問題的數目,隨着子
問題數目的增多,時間複雜度當然就增大了。
既然不同的狀態表示會描述不同大小的子問題空間,那麼原因何在呢?在這道題中
,我們僅僅從多邊形的定義來看,有這樣的關係:{連續多邊形} 是{半連續多邊形
}的子集,{半連續多邊形}是{多邊形}的子集。由此可知,應該是狀態表示描述子
問題不精確造成。
回顧狀態表示2-1和狀態表示2-2、2-3的分析,我們之所以採取狀態表示2-1 是基
於對多邊形自然特徵的認識,而沒有考慮到在特定環境下多邊形劃分而成的子多邊
形與多邊形本身有特殊的聯繫。比較狀態表示2-2、2-3,兩者都利用了多邊形劃分
的性質,但顯然研究的深度不同。狀態表示2-3保證了每種劃分都是對多邊形的不
同劃分,因爲至少有一條邊所在的三角形是與其他劃分中所在的三角形不一樣。狀
態2-2就不能保證這一點,如下圖所示的兩種劃分順序得出了同一種劃分。因爲這
種無意義的劃分而產生的多邊形屬於{半連續多邊形}-{連續多邊形},如半連續多
邊形(1,3,5)。

狀態表示的改進不僅僅使動態規劃的性能提高,通常也會使算法實現更加簡潔。比
較算法[2-2]、[2-3]我們就可以看出這一點。算法[2-3]的程序見附錄。
以上,我們主要討論狀態表示描述的子問題空間不同而影響動態規劃。這是狀態表
示影響動態規劃性能的主要原因,但是在算法實現過程中,由於某種原因我們可能
對同一子問題採取了不同的描述方法,存儲空間會產生極大的差異。下面這個例子
說明了這個問題。
問題三: “#”這個操作符被定義爲一個雙目運算符,且兩個運算對象爲正整數,
對於整數X,Y,# 號運算定義爲(X#Y)=十進制數X各數字之和*十進制數Y的最大
數字+十進制數Y的最小數字。例
(9#30)=9*3+0=27,(30#9)=3*9+9=36
對於表達式我們約定或是一正數或是(表達式#表達式)。以下表達式是合法的表
達式
a
(a#a)
((a#a)#a)
(a#(a#a)#(a#a)#a))
對於給定的十進制正數a和表達式的值K,計算具有K值的表達式中“#”的個數。具
有k值的表達式可能有許多,並且具有不同的#個數,只需輸出最小個數。a,k是均
不大於1000000000的正整數。

運算時,我們描述的是正整數k的各位數字和、最大數字和最小數字兩個信息(這
裏把最大、最小數字看成一個信息)以及得到k所用的最少 # 數,那麼可以有兩種
狀態表示。
狀態表示3-1
我們用一元組(k)表示正數k, D(k)表示所用的#數目。(k)已經隱含了各數字和、
最大數字和最小數字兩個信息。
狀態表示3-2
因爲對每個數而言,各位數字和與最大數字、最小數字兩個信息具有獨立性,我們
可以分別記錄這兩個信息。用一元組(X)表示各位數字和,用二元組(Y,Z)表示
最大數字、最小數字。
我們對輸入的數a進行特殊處理,而一次運算後的最大數字不超過738,狀態表示
3-1只要開一個數組,定義如下
Type NumBerType = array[1..738] of integer 
因爲一次運算後的數值最大是三位數,各位數值和不超過27,用來存儲數值和的數
組可定義爲
Type TotalType = array[1..27] of integer
最大數字、最小數字與數大小無關,它們範圍在[0,9],定義爲
Type MaxMinType = array[0..9,0..9] of integer 
狀態表示3-1用一元組同時記錄了兩個信息,而狀態表示3-2則分別記錄了這兩個信
息。顯然狀態表示3-2所用的空間比狀態表示3-1所用的要小的多。同樣一個對象,
只是由於我們採取不同的描述方法,所用的空間大小就迥然不同。程序見附錄。

綜上所述,狀態表示對動態規劃的性能的影響是多方面的。因此,在解決問題時,
從各方面比較狀態表示,根據具體情況選擇高效的狀態表示,才能進一步優化動態
規劃。

四、多路徑問題的狀態表示

  動態規劃是一個非常高效的算法,但是對於一些問題它並不是一個理想的算法
,這裏面的原因很多,最主要的原因是它的維數障礙。
下面就多路徑問題來說明這點。

問題四:
   存在一個數字梯形,最上層有m個數字,最底層有n個數字,每一層比上一層 多一個數字,共有n-m+1層數字,如圖是m=2, n=4的數字梯形。從頂到底有多條路
徑,每一步可沿左斜線向下或沿右斜線向下。路徑所經過的數字之和稱爲路徑得分
,從頂到底的m條不相交路徑的得分總和稱爲m條路徑得分,求出最小的m路徑得分


    2 3 2 3 
  3 4 5 3 4 5
9 1 9 1 9 1 9 1
最小的m路徑得分=15 

  顯然,這個問題與問題一極其類似。

  如果m=1, 那就是問題一所要解決的問題。

  如果m=2, 與問題一採取的方法類似,可以用D[x,y,z]描述兩條路徑到達第x層 y、z兩個位置的總得分。狀態轉移方程是
D[x,y,z] = Max{D[x-1,y,z],D[x-1,y,z-1],D[x-1,y-1,z],D[x-1,y-1,z-1]}
+A[x,y]+A[x,z], 
D[1,y,z] = A[1,y]+A[1,z]
 
  當m>=3時,可以採取類似m=2採用的狀態表示。
在狀態轉移方程中,第x層的得分只取決與x-1層的得分,利用這個性質,實現時只
要用兩個循環數組,空間複雜度爲O(nm)。

  當m恆定時,空間複雜度隨n呈多項式變化。當n恆定時,隨着m的增大空間複雜
度呈指數形式增長。
比如n=100 ,
當 m=2時,需要104 byte;
當 m=3時,需要106 byte;
當 m=4時,需要108 byte;

  我們看到當m=3時,基本的堆空間就不夠存儲了。在這個問題中,空間需要增長
極爲迅速,同時時間複雜度也是指數階的。目前動態規劃無法有效地處理這類問題
,科學家把動態規劃這樣的缺點稱爲動態規劃的維數障礙。它是兩方面的,包括空
間和時間, 但是在空間要求方面的障礙顯得特別突出。

  不論從空間上還是時間上考慮,動態規劃的維數障礙是難以克服的,這就在很
大程度上限制了動態規劃的應用。所以,我們必須尋找其他的方法來解決這類問題
。就這道題而言,網絡流是一個高效的算法。我們可以用最小費用流來解決問題,
流網絡大致構造如下:
把數字梯形看成是有向圖,對任意數字U看成兩個頂點u1、u2,容量c(u1,u2)=1, 費
用g(u1,u2)=U。若數字U沿對角線可到達數字V,則 c(u2,v1)=1, g(u2,v1)=0; 增加
超級源s, 對於第一層數字U分成的頂點u1, c(s,u1)=1, g(s,u1)=0; 增加超級匯t
,對於最底層頂點U分成的頂點u2, c(u2,t)=1,g(u2,t)=0; 其他頂點之間的容量爲
0。

五、總結
  動態規劃實現並不複雜,適用於許多問題,在解決一般問題時是我們首選的算
法之一。但是,動態規劃的數學模型的建立不是件容易的事,其中最困難也最重要
的是狀態表示。通過以上分析,我們看到:
1、動態規劃的狀態表示描述的子問題必須滿足最優子結構性質,否則無法建立正
確的動態規劃模型。
2、同一問題可能存在多種正確狀態表示方法,它們對應的動態規劃算法的性能各
不相同,從中選擇高效的狀態表示是動態規劃優化的一個重要內容。
3、對同一狀態表示而言,優化它的實現方法對改進動態規劃性能很有意義。
4、在應用動態規劃方法解決問題時,應先估計問題的時間、空間,如果問題存在
維數障礙,那麼動態規劃的狀態表示很難滿足較大規模問題的空間要求, 我們必
須另尋其他方法。


發佈了90 篇原創文章 · 獲贊 1 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章