動態規劃演算法舉例解析(最大收益和最小損失選擇)

2021-07-24 04:13:02 字數 3341 閱讀 8499

在說動態規劃的例子之前,先說明一下動態規劃和分治演算法的區別

雖然兩者都是通過組合子問題的解來求解原問題但是分治方法將問題劃分為互不相交的子問題,遞迴的求解子問題再將它們的解組合起來求出原問題的解。

而動態規劃演算法應用於子問題重疊的情況,即不同的子問題具有公共的子子問題,在這種情況下,分治演算法會做許多不必要的工作,它會重複的求解這些子問題,儘管這些子問題都曾經計算過。而動態規劃演算法就聰明了很多,它對每個子子問題都只求解一次。將其解儲存在乙個資料結構中,從而遇到曾經計算過的子子問題並不是再計算而是從這個資料結構直接取結果即可。

學習動態規劃演算法,首先要了解最優子結構這個概念

如果乙個問題的最優解包含其子問題的最優解,我們就稱此問題具有最優子結構性質,乙個問題如果可以應用動態規劃演算法,那麼它必然具有最優子結構。在使用動態規劃方法時,我們要利用子問題的最優解來構造原問題的最優解。

下面舉乙個例子,其實也是書上的例子

例子1,如何切割鋼條,長度為n的鋼條,可以選擇切割成多段也可以選擇不切割。這完全要依靠收益來看。下面這個表示長度為i的鋼條所對應的**表

長度i       1         2        3         4          5           6          7           8         9      10

**pi      1        5       8         9          10          17       17         20        24     30

比如乙個長度為4的鋼條,它的切割情況就有

方案                    收益

(1,3)---------- 9

(2,2)-----------10

(3,1)-----------9

(1,1,2)---------7

(1,2,1)---------7

(2,1,1)---------7

(1,1,1,1)-------4

(4,0)-----------9

這些方案中將長度為4的鋼條切割成(2,2)的收益最大,於是企業就會切割了賣。。。。

首先看這個問題滿足使用dp的最優子結構的性質。

我們第一次選擇切割鋼條的問題,剩下的鋼條則是與原問題相似的子問題。

其實原問題的最優解就是由第一次切割得到的兩段鋼條的最優切割方案組成的,符合最優子結構。這裡為了盡可能減少子問題空間的大小,切割後剩下的鋼條構成乙個子問題。剩下的鋼條可能還會被切割,也可能不被切割,這裡我們不管,我們只要求得在當前切割方案下這個子問題的最優解,與當前切割方案組合最優則能得到原問題的最優切割方案。

對於第一步的切割,你假定已經知道第一部應該如何切割得到最優解了,並且你知道第一步切割會產生怎麼的子問題。

可以利用剪下貼上的思想來驗證鋼條切割問題用動態規劃的思想來進行,假設子問題的解不是它自身的最優解,那麼我們可以從原問題中把子問題的解減掉,將子問題乙個更優的解放到原問題的最優解中,那麼將形成乙個比原問題最優解更優的方法,這與全問題最優解是矛盾的,所以如果要想達到原問題的最優解,必須子問題步步是最優的才是可行的。

將乙個長度為4的鋼條切割,僅僅使用了乙個子問題,(長度為4-i鋼條的切割),但i的值可能取0,1,2,3,就是第一次要切割的位置在長度為4的鋼條上的位置,下面則是一棵遞迴呼叫樹。可以看出要求長度4的鋼條最優切割方案,我們需要求解長度為3、2的切割方案,對應的則是i=1,i=2,這是剩餘各條需要切割的,節點為1和0的部分不需要切割,所以可以看到它的子樹沒有或者是0.

畫框的部分代表如果不採取措施就會重複計算的部分。樸素的自頂向下的動態規劃會造成重複計算的問題,時間複雜度高,加入了備忘機制的自頂向下的動態規劃可以避免這一問題,將計算出的結果放在列表中,如果還需要這部分值則直接取即可。另外自底向上的動態規劃可以更好的達到備忘機制的效果,想得到4的切割方案,先計算出3的方案,想得到2的切割方案,先得到1的方案,直到0,而0是初始設定,這裡長度為0的鋼條自然是沒有收益的。用了就是先把小粒度的計算出來在得到大粒度的思想。下面針對這三種方案分別實現

package dp;

public class cut_rod

int q = integer.min_value;

for(int i=1;i<=n;i++)

return q;

} public static int memoized_cut_road(intp,int n)

int q;

if(n==0)else

} return q;

}public static int bottom_up_road(intp,int n)

array[j] = q;

}return array[n];

} public static void extended_bottom_up_rod(intp,int n)

} static int max(int n1,int n2)

public static void main(string args) ;

/*system.out.print(cut_rod(p,4));*/

/* system.out.print(memoized_cut_road(p,4));

system.out.print(bottom_up_road(p,4));*/

print_road_solution(p,9);

}}

例子2,矩陣鏈乘法,給定乙個n個矩陣的序列,我們計算矩陣鏈乘積a1*a2*....an,用加括號的方式來明確計算次序,然後利用標準的矩陣相乘演算法進行計算,使得計算量最小,這裡的計算量用標量乘法的次數來表示作為計算的代價。

比如a1為10*100,a2為100*5,,a3為5*50,(a1*a2)*a3的計算量為10*100*5+10*5*50=7500,a1*(a2*a3)的計算量為10*100*50+100*5*50=75000,顯然按照第一種計算順序的計算代價更小一些,這裡就是在這樣的背景下提出了利用三種方式(自頂向下、加入備忘機制、自下向上)來分別計算的。

package dp;

public class matrix_multiply

int q = integer.min_value;

int m = new int[j+1][j+1];

m[i][j] = integer.max_value;

for(int k=i;k<=j-1;k++){

q = recursive_matrix_chain(p,i,k)+recursive_matrix_chain(p,k+1,j)+p[i-1]*p[k]*p[j];

if(q

動態規劃演算法解析

數字三角形 poj1163 在上面的數字三角形中尋找一條從頂部到底邊的路徑,使得路徑上所經過的數字之和最大。路徑上的每一步都只能往左下或 右下走。只需要求出這個最大和即可,不必給出具體路徑。三角形的行數大於1小於等於100,數字為 0 99 輸入格式 5 表示三角形的行數 接下來輸入三角形 3 88...

動態規劃演算法最大欄位和摘要 動態規劃演算法詳解

動態規劃 dynamic programming 是一種在數學 電腦科學和經濟學中使用的,通過把原問題分解為相對簡單的子問題的方式求解複雜問題的方法。動態規劃常常適用於有重疊子問題和最優子結構性質的問題,動態規劃方法所耗時間往往遠少於樸素解法。動態規劃背後的基本思想非常簡單。大致上,若要解乙個給定問...

動態規劃演算法

一 動態規劃演算法原理 將待求解的問題分解成若干個相互聯絡的子問題,先求解子問題,然後從這些子問題的解得到原問題的解 對於重複出現的子問題,只在第一次遇到的時候對它進行求解,並把答案儲存起來。了不去求解相同的子問題,引入乙個陣列,把所有子問題的解存於該陣列中,這就是動態規劃所採用的基本方法。動態規劃...