1. 程式人生 > >遞迴結構中的動態規劃

遞迴結構中的動態規劃

表示式上的動態規劃 最優矩陣鏈乘

給出n個矩陣組成的序列,設計一種方法把它們依次乘起來,使得總的運算量儘量小。假設第i個矩陣Ai 是Pi-1 X Pi的。

  • 用狀態f(i,j)表示i到j矩陣間的運算量,狀態轉移方程:
f(i, j) = min { f(i, k) + f(k+1, j) + P(i-1)P(k)P(j) }, i <= k < j 

凸邊多邊形上的動態規劃最優三角剖分

對於一個n個頂點的凸邊多邊形,有很多種方法可以對它進行三角剖分,即用n-3條互不相交的對角線把凸邊多邊形分成n-2個三角形。為每個三角形規定一個權函式f(i,j,k) (如三角形的周長或三個頂點的權和),求讓所有三角形權和最大的方案

  • 定義f(i,j) 為“從頂點i到頂點j所構成的子多邊形的最大三角剖分權和”,則邊PiPj在此多邊形內一定恰好屬於一個三角形 iPjPk,只要列舉k的位置,就能把多邊形分割成兩部分。注意到兩個多邊形的頂點序列仍是連續的,因此有狀態轉移方程:
    f(i, j) = max { f(i, k) + f(k, j) + w( i, j, k) }

先了解下矩陣鏈乘:點選這裡

最優三角剖分推薦網址:點選這裡樹上的動態規劃樹的最大獨立集

對於一棵n個節點的無根樹,選出儘量多的節點,使得任何兩個節點均不相鄰(稱為最大獨立集),然後輸入n-1條無向邊,輸出一個最大獨立集(如果有多解,則任意輸出一組)。

分析:

用d(i)表示以i為根節點的子樹的最大獨立集大小。此時需要注意的是,本題的數是無根的:沒有所謂的“父子”關係,而只有一些無向邊。沒關係,只要任選一個根r,無根樹就變成了有根樹,上述的狀態定義也就有了意義了。

節點i只有兩種決策:選和不選。如果不選i,則問題轉化為了求出i的所有兒子的d值再相加;如果選i,則它的兒子全部不能選,問題轉化為了求出i的所有孫子的d值之和。換句話說,狀態轉移方程為:

\small d(i)=max\left \{ 1+\sum_{j\in gs(i)}{d(j)},\sum_{j\in s(i)}{d(j)} \right \},其中gs(i)和s(i)分別為i的孫子集合與兒子集合.

程式碼該如何寫呢?上面的方程涉及“列舉節點i的所有兒子和孫子”,頗為不便。其實可以換個角度來看:不從i找s(i)和gs(i)的元素,而從s(i)和gs(i)的元素找i。換句話說,當計算出一個d(i)後,用它去更新i的父親和祖父節點的類加值\small \sum_{j\in gs(i)}{d(j)}

\small \sum_{j\in s(i)}{d(j)}。這樣一每個節點甚至不必記錄它的兒子的節點有哪些,只需記錄父親節點即可。

傳統的遞推法可以表示成“對於每個狀態i,計算f(i)”,或者成為“填表法”。這需要對於每個狀態i,找到f(i)依賴的所有狀態,在某些時候並不方便。另一種方法是“對於每個狀態i,更新f(i)所影響到的狀態”,或者稱為“刷表法”,有時比填表法方便。但需要注意的是,只有當每個狀態所依賴的狀態對它的影響相互獨立時才能用刷表法。例如,在最優矩陣鏈乘問題中就無法直接使用刷表法。