[Optimization] Advanced Dynamic programming

這裏主要是較爲詳細地理解動態規劃的思想,思考一些高質量的案例,同時也響應以下這麼一句口號:html

「迭代(regression)是人,遞歸(recursion)是神,動態規劃是what?」node

Video series for Dynamic Programminggit


 

Planning a company party

Ref: http://mypathtothe4.blogspot.com.au/2013/03/dynamic-programming-company-party.html算法

 

Stewart教授是一家公司總裁的顧問,這家公司計劃一個公司聚會。這個公司有一個層次結構;也就是,管理關係造成一棵以總裁爲根的樹。人事部給每一個僱員以喜歡聚會的程度來排名,這是一個實數。爲了使每一個參加者都喜歡這個聚會,總裁不但願一個僱員和他(她)的直接上司同時參加。shell

生成一張客人列表,使得客人喜歡聚會的程度的總和最大。安全

 

Naive Recursive Solution

Idea 1session

    1. 變成了從大集合中挑N我的組合,固然,最好是由多到少的選人。
    2. 而後判斷這個集合是否知足狀況。

 

Idea 2app

Find-Max-Conv(Node n) if n.children = null
        return max(0, n.rating) 
return max( Sum(Find-Max-Conv(i)) for all i = n.children), Sum(Find-Max-Conv(i) for all i = n.grandchildren) + n.rating)

//return 的內容有問題,不過沒關係

 

Let's take a quick look at what this recursion does: the base case (leaves) in lines (1, 2) simply returns the max value of not 0 (not inviting someone) and the conviviality rating of the person. (We need the comparison with 0 in case the conviviality is negative). Line 3 is our recursive call; the solution, given some node, will be the maximum of inviting the current node (person) and not inviting the current node (person). If we invite the current node, we cannot invite children, and thus we sum the current value with the maximum ratings of the current node's grandchildren. If we don't invite the current node, then the maximum value would be the sum of maximum convivialities over all children.

Consider the running time of this algorithm. We go through every node in the tree, and consider adding or not adding it. So there are two options for each of n nodes (0, 1), meaning the number of operations will be some function of 2^n. This is exponential running time and undesirable.ide

 

Dynamic Programming

如何尋找sub-problem。ui

The principal idea then, is to start from node n and work back to the root, each time basing the current optimal conviviality on previously computed sub-problems that have been stored in some memoization table.

Find-Max-Conv(Tree t) Let MC[ ] be an array of length n that contains max conviviality from this node down in the tree
for i = Node n down to 1 MC[i] = max(i.rating + Sum of all MC[i.grandchildren], Sum of all MC[i.children]) (If node i has no grandchildren or children, replace i.grandchildren and/or i.children with 0) return MC[1]

 

尋找子問題

節點(青綠)不參加的話,孩子都能參加。那麼孩子的高興值在sub-problem中應該是計算過了,保存在MC[]中。

節點(暗灰)若參加的話,孩子不能參加。那麼孫子的高興值在sub-problem中應該是計算過了,保存在MC[]中。

計算n個節點的SelectRoot和UnselRoot,每次計算都只使用子節點的域值,因此整個計算的過程也只累加了樹中除了根的其它節點的域值(每一個節點就被用一次)。因此算法複雜度爲O(n)。

 

 

 

Find if a string is interleaved of two other strings

Ref: http://www.geeksforgeeks.org/check-whether-a-given-string-is-an-interleaving-of-two-other-given-strings-set-2/

For example A = 「XXY」, string B = 「XXZ」 and string C = 「XXZXXXY」

 

兩個字符串交叉獲得的字符串,其中隱含了"順序性"

 

Naive Recursive Solution

如下方式至關於遍歷完了全部狀況,有點圍棋窮舉的意思。

// A simple recursive function to check whether C is an interleaving of A and B
bool isInterleaved(char *A, char *B, char *C) { // Base Case: If all strings are empty
    if (!(*A || *B || *C)) return true; // If C is empty and any of the two strings is not empty
    if (*C == '\0') return false; // If any of the above mentioned two possibilities is true, // then return true, otherwise false
    return ( (*C == *A) && isInterleaved(A+1, B, C+1)) || ((*C == *B) && isInterleaved(A, B+1, C+1)); }

The worst-case time complexity of the recursive solution is O(2n).  // 從return的形式可見"二叉樹的node的擴展方式"

The above recursive solution certainly has many overlapping subproblems. For example, if we consider A = 「XXX」, B = 「XXX」 and C = 「XXXXXX」 and draw recursion tree, there will be many overlapping subproblems.
Therefore, like other typical Dynamic Programming problems, we can solve it by creating a table and store results of subproblems in bottom up manner. 

 

Dynamic Programming

Algorithm:

  

s1 = 「aabcc」       <- x
s2 = 「dbbca」       <- y
s3 = 「aadbbcbcac」  <- z

 

尋找子問題

理解:

當len z = 4時,只會是len x + len y = 4的狀況;

那麼,這些狀況中的一些,是在sub-problem中解決了的;

在表格中,只需關心「子問題」爲T的格子,以及臨近的兩個格子(右,下)。

 

Idea:

在已有的能夠的狀況下的頭頂加一個合格的帽子是沒問題的。

不影響sub-problem的內部合理性,帽子也是知足

"If z is the interleaving of x and y, it contains a subproblem z'= z1...zm+n−1 and the last bit zm+n must be xm or yn."

 

len z = 4時(黃色格子),sub-problem的結果就是桔黃色的格子以下。

進一步地,規律以下,T的方格構成的必須是連通圖。

 

 

  

Weights and Measures - Turtle Tower

 

 

疊烏龜問題:極其經典,研究價值五星 - 你值得擁有! - 由於五星,因此配圖。

From: http://cgi.cse.unsw.edu.au/~cs3121/Lectures/COMP3121_Lecture_Notes_DP.pdf

 

You are given n turtles, and for each turtle you are given its weight and its strength.

The strength of a turtle is the maximal weight you can put on it without cracking its shell.

Find the largest possible number of turtles which you can stack one on top of the other without cracking any turtle.

 

Naive Recursive Solution

  /* 很是複雜,不太現實 */

 

 

Dynamic Programming

Subproblem P(j): Find the largest possible number of turtles from the set {T1 , . . . , Tj } 
which you can stack one on top of the other without cracking any turtle.

常規"子問題"沒辦法迭代!

思考:10個龜狀況下的疊起來的方案,可否用於加了一個11th龜後的狀況?

P(11) 的全部子狀況是:

    • P(10)的最優解
    • P(09)的最優解
    • ...
    • P(01)的最優解

那麼,P(11) 能利用這些麼?

    • new P(11)的最優解中T11是最下面的位置麼?
    • new P(10)的最優解中T11是最下面的位置麼?
    • new P(09)的最優解中T11是最下面的位置麼?
    • ...
    • new P(01)的最優解中T11是最下面的位置麼?

不能保證!

加一個「龜」,會破壞子問題的situation,致使必須從新思考「子問題」

故,new P(09)的最優解就不是extension of P(09) 的最優解。

 

如何找到正確的「子問題」

那什麼feature才能保證永遠在最優方案最下面的位置呢?

推理一 

Answerstrength + weight

 

Thus, we order turtles according to the sum of their strength plus their weight, i.e., assume that for all i, j ≤ n

關於這個意義在於,它保證了一種疊海歸的方案,這個方案的最底下的海龜是新海龜,由於它的strength + weight最大。

本就是按照有小到大的順序依次處理的嘛。更直接地說:Tj相對於已有在處理的海龜集都是最大的。

也就是說:子問題擴展的時候,提供了一種安全的「添加一個海龜」的順序

 

感性理解

To guarantee that optimal towers can be obtained from the previous optimal towers

we build a sequence of lightest possible towers of every possible height. 

P(10) height:3 的構造過程:

        

T10 若能承受w1+w2,則T10一定在最底下。     <-- 保證了recursion的可行性!

T10 不能承受w1+w2,則無論如何排12T10 都是不可能的。

假設,1,2都是隻能承受一個node的主兒,那麼height:3時,就會是右圖所示,去掉了2。

Key理解:

"在P(10) height:3可行的大前提下,如此,一定真正的P(10) height:3就是這麼組合的了"

何爲"可行"?就是直接看sT10 > w1+w2就是可行。(由於有推理一做爲保證)

 

P(10)  // Now

      • height 1  --> 若干results, 只選最輕的那一個
      • height 2  --> 若干results, 只選最輕的那一個
      • height 3  --> 若干results, 只選最輕的那一個
      • ...
      • height 10 --> 若干results, 只選最輕的那一個

 

P(09)  // Sub-problem

      • height 1 --> 若干results, 只選最輕的那一個
      • height 2 --> 若干results, 只選最輕的那一個
      • height 3 --> 若干results, 只選最輕的那一個
      • ...
      • height 9 --> 若干results, 只選最輕的那一個

etc.

Thus, we solve the following generalisations of our problem, for every j ≤ n:

 

 

Subproblem P(j):

For each kj for which there exists a tower of turtles of length k built from turtles {T1, . . . , Tj} (not necessarily containing Tj ),

find the lightest one.

  

Recursion:

With this subproblem, we can solve any P(i) like this:  // P(10)

*************************************************************

To obtain the lightest tower θ(k, i) of any height k built from turtles {T1,...,Ti},  // θ(k, 10): P(10)下的一系列heigh k = 3

we look at

    • the lightest tower θ(k, i−1) of height k                                                               // θ(k, 09): P(09)下的一系列heigh k = 3

    • the lightest tower θ(k-1, i−1) of height k − 1                                                     // θ(k, 09): P(09)下的一系列heigh k-1 = 2

both built from turtles T1,T2,...,Ti−1, which we have got in the sub-problem P(i-1).

*************************************************************

有了已解決的子問題,那麼,我們就開始判斷咯:

    • If the tower obtained by extending θ(k-1, i−1) with Ti is both legitimate and lighter than θ(k, i−1), we let θ(k, i) be such a tower. (this means Ti contributes to a better lightest tower with more Residual Capacity)

    • Otherwise we let θ(k, i) = θ(k, i−1).

能夠如此理解:

  新轉來一名學生,只要比較她跟班裏的第三名成績就行了:

  * 比第三名好的話,就拿前兩名加這個新生構成新的top3;

  * 沒第三名好的話,原來的top3依然保留地位。

 

Finally, we obtain the lightest tower θ(k, i) of any height k for P(i).

 

The solution to our problem is now obtained from the solution to P(n) by picking the longest tower obtained by solving P(n).

 

 

 

Box Stacking Problem

 video講解:https://people.cs.clemson.edu/~bcdean/dp_practice/dp_5.swf

The Box Stacking problem is a variation of LIS problem. We need to build a maximum height stack.

Following are the key points to note in the problem statement:

1) A box can be placed on top of another box only if both width and depth of the upper placed box are smaller than width and depth of the lower box respectively.

2) We can rotate boxes. For example, if there is a box with dimensions {1x2x3} where 1 is height, 2×3 is base, then there can be three possibilities, {1x2x3}, {2x1x3} and {3x1x2}.

3) We can use multiple instances of boxes. What it means is, we can have two different rotations of a box as part of our maximum height stack.

 

Following is the solution based on DP solution of LIS problem.

1) Generate all 3 rotations of all boxes. The size of rotation array becomes 3 times the size of original array. For simplicity, we consider depth as always smaller than or equal to width.

2) Sort the above generated 3n boxes in decreasing order of base area.

3) After sorting the boxes, the problem is same as LIS with following optimal substructure property.

MSH(i) = Maximum possible Stack Height with box i at top of stack  // 這個頂上的 box i 是強制安排的

MSH(i) = { Max ( MSH(j) ) + height(i) } , where j < i and width(j) > width(i) and depth(j) > depth(i).

If there is no such j then MSH(i) = height(i)

4) To get overall maximum height, we return max(MSH(i)) where 0 < i < n

 

 

 

Bin-packing problem

傳統的三種方式:https://www.youtube.com/watch?v=kiMFyTWqLhc

Full-bin packing Algorithm中已體現出了動規的影子,或者叫必要性。

 

要確保獲得最優的答案,還得看動規,如下是一些可能有用的參考連接。

ref: https://www.youtube.com/watch?v=wy45-JH8_yY

ref: http://www.sciencedirect.com/science/article/pii/S0377221706004310?via%3Dihub 

 

Idea: (核心思想)

opt(i, j, p)是由一堆子問題堆積起來的,or 推起來的。

關鍵在於理解這個opt(i, j, p)和下面子問題之間的關係,要如何創建之間的邏輯關係。

 

子問題:

條件: s1 = 2,  s2 = 3,  s3 = 5,  C = 10 (size of bin)

 

i = 7, j = 3, p = 3  
opt(i-5, j, p) opt(i-3, j-1, p) opt(i-2, j-2, p) opt(i, j-3, p) opt(i-2, j, p-1) opt(i-1, j-2, p-1) opt(i, j, p-2)  
opt(2, 3, 3) = 3 4, 2, 3 5, 1, 3 7, 0, 3 5, 0, 2 6, 1, 2

7, 7, 0

sub-p

 

  opt(0,1,3) = 2 bin 2,0,3 0,3,2 1,1,2 2,3,1 sub-p of 2,3,3
           

opt(0,1,1) = 1 bin

sub-p of 0,1,3

size: 2*2+3*3+3*5=28

暗含了一個道理:

多兩個s1和兩個s2是確定要

多一個bin的

 

size: 0*2+1*3+3*5=18

暗含了一個道理:

多兩個s3是確定要多一個bin的

         

可見,這是個六叉樹!孩子就是子問題。

遞歸是從上到下,貌似預分配了所需的全部空間,也就是六叉樹的全部node。

動規,則提供了自底向上的思路,每一個子問題僅保存了最優的結果(一個數值),這樣便節省了空間。

其實,這也體現了 prolog language 解決問題的思路,以及設計原理,即:

解決遞歸問題,選擇prolog會更加高效,方便。

IDE online: http://potassco.sourceforge.net/clingo.html

相關文章
相關標籤/搜索