1. 程式人生 > >關於動態規劃演算法的總結

關於動態規劃演算法的總結

動態規劃演算法,在T大某位老師的書中說就是遞推+重複子問題。

動態規劃演算法的效率主要與重複子問題的處理有關。

典型的題目有 陪審團,最大公共子串問題

1,最大公共子串問題

這個是動態規劃的基礎題目。動態規劃就是遞推和重複子結構。

確定了遞推關係後。找到一個能極大地減少重複運算的子結構至關重要。選的好了,時間效率會很好。

這個問題,不妨設第一個串為a,長度為n,第二個串為b,長度m。那麼最長的子序列長度為f(n,m)

當a[n]=a[m]時

f(n,m)=1+f(n-1,m-1)

否則f(n,m)=max(f(n-1),f(m-1))

同時建立一個儲存計算過的f(x,y)的矩陣,如果計算過了就直接使用

程式如下所示

 

2,陪審團問題

問題描述:

問題描述
在遙遠的國家佛羅布尼亞,嫌犯是否有罪,須由陪審團決定。陪審團是由法官從公眾中
挑選的。先隨機挑選n 個人作為陪審團的候選人,然後再從這n 個人中選m 人組成陪審團。
選m 人的辦法是:
控方和辯方會根據對候選人的喜歡程度,給所有候選人打分,分值從0 到20。為了公
平起見,法官選出陪審團的原則是:選出的m 個人,必須滿足辯方總分和控方總分的差的
絕對值最小。如果有多種選擇方案的辯方總分和控方總分的之差的絕對值相同,那麼選辯控
雙方總分之和最大的方案即可。最終選出的方案稱為陪審團方案。
輸入資料
輸入包含多組資料。每組資料的第一行是兩個整數n 和m,n 是候選人數目,m 是陪審
團人數。注意,1<=n<=200, 1<=m<=20 而且 m<=n。接下來的n 行,每行表示一個候選人
的資訊,它包含2 個整數,先後是控方和辯方對該候選人的打分。候選人按出現的先後從1
開始編號。兩組有效資料之間以空行分隔。最後一組資料n=m=0
輸出要求
對每組資料,先輸出一行,表示答案所屬的組號, 如 'Jury #1', 'Jury #2', 等。接下來的
一行要象例子那樣輸出陪審團的控方總分和辯方總分。再下來一行要以升序輸出陪審團裡每
個成員的編號,兩個成員編號之間用空格分隔。每組輸出資料須以一個空行結束。
輸入樣例
4 2
1 2
2 3
4 1
6 2
0 0
輸出樣例
Jury #1
Best jury has value 6 for prosecution and value 4 for defence:
2 3

用動態規劃來解

動態規劃可以看成是重複子問題+遞迴

設p為控方向量,d為辯方向量

評分從-400到400
f(j,k)為選取第j個人,評分差為k的辯控總分
對於任意的i,i大於0小於n,則有
f(j,k)=f(j-1+1,x+p[i]-d[i])
則就有
f(j,k)=f(j-1,x)+p[i]+d[i];

如果新的f(j,k)大於舊的,則替換舊的,否則不替換

初始值為k=0,在程式中或許是某個值,以免避免序號k出現負值。
那麼初始的f(0,0)=0;
在第一輪的時候只有辯控差為0的合理
對所有的候選人做
f(1,p[i]-d[i])=max(f(1,p[i]-d[i]),f(0,0)+p[i]+d[i]);
這樣就可以完成選一個人的操作。
做完之後離k=0最近的非負的就是我們要的最大的辯控和。下標就是辯控差。
同理,如果選兩個的話,第二輪
k=-400~400
如果f(1,k)合理(此時,只有在第一輪中算出來的合理)
f(2,k+p[i]-d[i])=max(f(2,k+p[i]-d[i]),f(1,k)+p[i]+d[i]);

如果要儲存搜尋得到的路徑
設路徑path儲存路徑向量
path(j,k)儲存推薦第j個陪審員時候,辯控差為k的候選人。
對應上面的f函式,初始值都設為0。
如果只找一個候選人
則本身path中沒有任何的值,即沒有推薦任何的人。也就是說,推薦第一個人的時候,誰都可以(若推薦第二個人,則以前推薦過的不能再次推薦)
在推薦第一個候選人的時候,只管儲存path[0][p[i]-d[i]]=i ;

當選取多個候選人的時候,在更新f(j,k)的同時更新path,因為更新f(j,k)的同時,意味著選了新的候選人,所以需要更新路徑


當以上都做完之後,
定義一個數組result來取路徑
對i:1~m
 result[i]=path[m-i+1][k];
 k=k-p[result[i]]+d[result[i]];
這樣就都解決了。

 

3,小花店問題

F束花從左到右放在V個花瓶裡面(1<=F<=V<=100),花要按照花的標誌數從小到大排列。不同的花在不同的花瓶能夠產生不同的美學價值。v[i,j]來表示第i朵花在第j個花瓶產生的美學價值。求把n朵花放在m個花瓶能夠產生的最大的美學價值。

這個題和最大公共子串的思考角度相似。由於花必須要小於等於瓶子。而且花的編號由小到大,不能亂序。例如就不能把出現【2,4】 【1,5】這種現象。也就是說插在花瓶中的花按照花瓶的順序,序號升序排列。

  不妨用f(i,j)來表示把前i朵花插入前個瓶子中。當i=j時,f(i,j)=v[1,1]+v[2,2]+...+v[i,i];

當i=0時,f(0,j)=0; 當i!=j, 且i!=0時f(i,j)=max(f(i,j-1),f(i-1,j-1)+v[i,j]) ,i<=j-1.

 4,最佳旅行線問題

簡單描述:某航空公司給的獎品,一張免費的機票。可以從最西邊的一個城市出發,必須到達最東邊的一個城市,然後返回起點城市。每個城市職能經過一次,起點被訪問2次。問最多能夠訪問多少個城市。

這個題可以使用動態規劃的方法。這個題目也使我想起了《演算法導論》中裝配線的問題,其實基本是一致的。

在很多的書或者是解法中,都用了這樣的方法:從起點開始,兩條路一起走f[i,j]表示兩條不相交的路線分別到達i和j時,所需乘坐航線的最大值

f(1,1)=0;

f(i,j)= max{f(k,j)}+1,i>j ;k是i的前驅節點。

         max{f(i,k)}+1,i<j

f(i,i)無意義

該演算法是沒有錯的。很多地方也用這個演算法做了一些程式版本。但是這個演算法有一個限制,就是前驅節點。在t大某位老師的書中,他列舉所有的點對,然後對f矩陣進行更新(傳統的動態規劃方法)。但是他這個有一個前提,那就是所有節點的序號符合拓撲序列。但是題目中並沒有說城市符合拓撲序列。假如說序號比較隨意,t大的這本書中的就錯了。但是他並沒有在程式碼中說明,算是對讀者的一個誤導。

 

 

5, 最長詞鏈問題

給定一個僅僅包含小寫字母的英文單詞表,其中每個單詞至少包含一個字母,最多包含75個字母,且按照字典序排列。所有單詞包含的單詞個數之和不超過200w

     如果在一張由一個單詞或者多個單片語成的表中,每個單詞都被其後的一個單詞所包含,則成此表為一個鏈。

     現在要求從單詞表中找到一個包含單詞書最多的最長詞鏈。

該問題可以由動態規劃解。這讓我想起了一個題:在一個連續的長字串中,找出匹配次數最多的一個片語,不能有重疊。相同的方法。

令F(k)表示第k個單詞的時候的最長的鏈。則F(k)=maxF(i)+1,i從1,到k-1,並且第i個單詞是第k個的字首。這兒問題就解了。

但是,對於這道題還有其他的解法。由於字典序並非亂序。每個單詞的前一個單詞所包含的字首很可能就是這個單詞的字首,並且前一個單詞也可能就是該單詞的字首。因為字首的特殊性。所以只用檢查前一個單詞的字首(包括該單詞本身)就能找出該字首鏈

程式碼為非動態規劃演算法

6, 整數劃分問題

給定一個自然數,分成k部分,A1,A2..的數的和,要求A1<=A2...求有多少種?

原理:整數n拆分成最多不超過m個數的和的拆分數,和n 拆分成最大不超過m的拆分數相等。 根據這個原理,原問題就轉化成了求最大拆分為k的拆分個數與最大拆分為k-1的拆分個數的差 f(n,k)=f(n,k-1)+f(n-k,k)。   同時附上ferrer圖的幾個原理: a,整數n拆分成k個數的和的拆分數,和數n拆分最大數位k的拆分數相等 b,整數n拆分成最多不超過m個數的和的拆分數,和n拆分成最大不超過m的拆分數相等。 c,整數n拆分成互不相同的若干奇數的和的的拆分數,和n拆分成自共軛的Ferrers影象的拆分數相等.

7,青蛙的煩惱

池塘裡面有n片荷花,正好形成一個凸多邊形,按照順時針方向將這n片和也順次編號為1,2,3,4,5...,n。一隻青蛙想要跳過這些荷葉,每個只能跳過一次,希望跳過的距離最短。

輸入荷葉數n,每片荷葉的座標xy,輸出最短距離。

分析:凸多邊形,首先不能出現交叉路,否則,由兩邊之和大於第三邊可以知道,這樣實際上是路程變長了。

其次,直接按照凸多邊形也不正確,可以參考平行四邊形,其中一個角為30度,請自行畫圖查明。

方法:每次每個頂點只能到與自己相鄰的兩個中的一個(到其他頂點邊會出現交叉),剩下的n-1個頂點也遵從這一規則。則可以使用動態規劃的方法。

從s到L

則如果從s出發,則f(s,L,0)=min{dis(s,s+1)+f(s+1,L-1,0),f(s+1,L-1,1)+dis(s+L-1,s)}

如果從s+L-1出發則f(s,L,1)=min{dis(s,s+L-1)+f(s+L-1,L-1,0),f(s+L-1,L-1,0)+dis(s+L-1,s)}

8排列問題

在整數1,2,。。。,n中,有些排列滿足下面的性質:該排列中除了最後一個數字以外,每個整數後面都跟有一個同它相差為1的整數。例如:N=4,排列1432滿足上述性質。求,如果 任意指定p個位置的值,求最多有幾個排列滿足如上性質

這種排列滿足一下兩條性質

a,任何一個排列的後k位是若干連續整數的集合

b,如果一個排列的後k位(1<=k<=n)是軟干連續整陣列成的集合,則這個排列滿足題目所述的性質。

動態規劃的方法即可。設s為起始的數的大小,r為連續的多少數的個數

g(s,r)=g(s+1,j-1),若第1個位置為s,即倒數第j個位置為s

   g(s,j-1),若第1個位置為s+r-1,即倒數的第j個位置為s+r-1

   不確定則為上述兩個之和

程式碼如下

 

9,畫室問題

實際上該題可以描述為,給定一個尺寸為N的矩陣,行和列寬度為2^N,將該矩陣分為4分,左上角不為零,其他三部分都包含零。遞迴定義這三部分,直到最小單位,即矩陣只有一個數,為0;

求如果讓該矩陣移動一個尺寸(x,y),兩個矩陣重複部分的0的個數。

思考:實際上就是判斷移動前和移動後對應的位置是否都為0,如果都為0,則總0個數+1。

如果移動到了左上角的位置則不加,其他三部分因為是一樣的,該部分遞迴定義的上層+1

在下面的程式中,k1,k2 表示的位置,在當前區域的哪一塊

a,b表示三個區域,其中左上的直接被忽略了。

kk1,kk2,表示移動到的了哪一個區域

if(!((a+p[i-1]+k1)%2==0&&(b+q[i-1]+k2)%2==1))表示移動到的區域的哪一塊,如果是左上直接忽略

 

10, 中世紀劍士

n個人決鬥,兩兩之間有強弱關係,強弱關係不傳遞,例如a>b,b>c,c>a。n個劍士圍成一個圈,一次抽籤,抽中的人和他右邊的人決鬥,輸了的人出圈。現在問是否存在一種決鬥方式讓第k個人生出,計算可能勝出的的人數和方案。

這個題目讓我想起了圍成一個圈的猴子的題目,那個題目是約瑟夫問題。

和這個不一樣。

這個題目:一個人要勝出,則要勝了所有右邊的人,同時也要勝出左邊的人。因為是圍成一個圈,所以該人勝出的話,最終肯定是自己跟自己相遇。那麼,這種情況下,把圈展開成一個鏈,將該鏈延長一倍,如果i和i+n可以相遇,則說明i可以勝出。i人向右決鬥,i+n向左決鬥

如果兩個人可以相遇,用meet[i,j]來表示

meet[i,j]= true if meet[i,k] and meet[k,j] and (e[i,k] or e[j,k])=true

false

 

11, 科學家實驗隕石

總共獲得了n1塊A星的和n2塊B星的,每次實驗需要各一塊,實驗完了後不能回收。

總共實驗min(n1,n2);

求每次試驗的絕對值和的最小值

先證明一下兩個遞增序列,a1<b1,a2<b2,  |a2-a1|+|b2-b1|<=|b2-a1|+|b1-a2|

------a1----------------b1-------------

         - -

-

- O -

------a2----------------b2--------------

由上圖根據兩條邊之和大於第三邊可以直接證明上面的式子

所以就可以放心的使用動態規劃了

對兩列資料由小到大排序,少的用i表示,多的用j表示

F[i,j]=min(F[i,j-1],F[i-1][j-1]+dis(i,j))      j>i

  F[i-1][j-1]+dis(i,j)     j=i

程式設計暫時省略,因為這個題目比較簡單

12,理想收入問題

只有一元的本金,知道每天的股價為v[i], 求M天之後的理想收入,能夠獲得的最大的收入

假設第i天的理想收入為F[i]

則有F[i]=max(F[j]/v[k])*v[i]; j<=k<i

令M[i]=max(F[j]/v[k])=max(M[i-1],MF[i-1]/v[i]);M[i]表示在第i天可以得到的最多股票數,MF[i-1]表示前i-1天可以取得的最大收入

MF[i]=Max(MF(i-1),F(i-1))

13. 一般的RMQ問題 (Range Minimum/Maximum Query)

對於給定的N與N個整數A[1...N],M與M對下標(x,y)(x<=y),對於每對下標(x,y)求出A[x...y]中最小數的下標         解法:                 預處理,對於區間中每一個點A,設計以A為左端點的floor(logN)+1個區間                 [A,A+2^0-1], [A,A+2^1-1],...,[A, A+2^floor(logN)-1] 在求解的過程中,按照區間長度依次求解。[A,A+2^(i+1)-1],可以通過兩個等長的子區間[A,A+2^i-1]和[A+2^i,A+2^(i+1)-1];        取用方法: A,當區間的重疊對結果無影響的時候,例如求最大最小值(本題所述,則根據區間[A,A+2^k-1]與[B-2^k+1,B]來計算 B,當區間的重疊對結果有影響的時候,例如統計數字的多少等等,將[A,B]劃分為[A,A+2^k-1], [A+2^K,A+2^k+2^(floor(log(B-(A+2^k)+1)))-1],每次使用對數直接獲得劃分點。所以至多分成了floor(log(B-A+1))+1個區間。 所以這樣處理的時間複雜度為logN 本題中,所述的所有對數,均是以2為底。   本題中,開一個數組,行下標表示區間開始端A,列座標表示區間結束端B 14, 關於分石子問題的動態規劃解法

有n個石頭,k個框子。把n個石頭按順序放入k個框子,比如1~3放入1,4~6放入2,要求最大重量的框子的重量最小的放法。

設石子的重量分別為Q1,Q2,...

g(i,j)=Qi+,...,+Qj;

f(i,j)表示把i個石子放到j個框的最大重量框的重量。

則f(i,j)=minj-1<=p<i (f(i,j),max(f(p,j-1),g(p+1,i)));

g(i,i)=Qi ,f(1,1)=g(1,1),f(i,1)=g(1,i);

1<=i<=n;

1<=j<=k;

如果提前把Si =Q1+,..,+Qi 計算出來,g(j,k)=Sk -Sj-1 則時間複雜度為O(N2 )