動(dòng)態(tài)規(guī)劃 DP算法

多階段決策過程(multistep decision process)是指這樣一類特殊的活動(dòng)過程,過程可以按時(shí)間順序分解成若干個(gè)相互聯(lián)系的階段,在每一個(gè)階段都需要做出決策,全部過程的決策是一個(gè)決策序列。動(dòng)態(tài)規(guī)劃(dynamic programming)算法是解決多階段決策過程最優(yōu)化問題的一種常用方法,難度比較大,技巧性也很強(qiáng)。利用動(dòng)態(tài)規(guī)劃算法,可以優(yōu)雅而高效地解決很多貪婪算法或分治算法不能解決的問題。動(dòng)態(tài)規(guī)劃算法的基本思想是:將待求解的問題分解成若干個(gè)相互聯(lián)系的子問題,先求解子問題,然后從這些子問題的解得到原問題的解;對(duì)于重復(fù)出現(xiàn)的子問題,只在第一次遇到的時(shí)候?qū)λM(jìn)行求解,并把答案保存起來,讓以后再次遇到時(shí)直接引用答案,不必重新求解。動(dòng)態(tài)規(guī)劃算法將問題的解決方案視為一系列決策的結(jié)果,與貪婪算法不同的是,在貪婪算法中,每采用一次貪婪準(zhǔn)則,便做出一個(gè)不可撤回的決策;而在動(dòng)態(tài)規(guī)劃算法中,還要考察每個(gè)最優(yōu)決策序列中是否包含一個(gè)最優(yōu)決策子序列,即問題是否具有最優(yōu)子結(jié)構(gòu)性質(zhì)。

動(dòng)態(tài)規(guī)劃算法的有效性依賴于待求解問題本身具有的兩個(gè)重要性質(zhì):最優(yōu)子結(jié)構(gòu)性質(zhì)和子問題重疊性質(zhì)。

1、最優(yōu)子結(jié)構(gòu)性質(zhì)。如果問題的最優(yōu)解所包含的子問題的解也是最優(yōu)的,我們就稱該問題具有最優(yōu)子結(jié)構(gòu)性質(zhì)(即滿足最優(yōu)化原理)。最優(yōu)子結(jié)構(gòu)性質(zhì)為動(dòng)態(tài)規(guī)劃算法解決問題提供了重要線索。

2、子問題重疊性質(zhì)。子問題重疊性質(zhì)是指在用遞歸算法自頂向下對(duì)問題進(jìn)行求解時(shí),每次產(chǎn)生的子問題并不總是新問題,有些子問題會(huì)被重復(fù)計(jì)算多次。動(dòng)態(tài)規(guī)劃算法正是利用了這種子問題的重疊性質(zhì),對(duì)每一個(gè)子問題只計(jì)算一次,然后將其計(jì)算結(jié)果保存在一個(gè)表格中,當(dāng)再次需要計(jì)算已經(jīng)計(jì)算過的子問題時(shí),只是在表格中簡(jiǎn)單地查看一下結(jié)果,從而獲得較高的解題效率。

當(dāng)我們已經(jīng)確定待解決的問題需要用動(dòng)態(tài)規(guī)劃算法求解時(shí),通??梢园凑找韵虏襟E設(shè)計(jì)動(dòng)態(tài)規(guī)劃算法:

1、分析問題的最優(yōu)解,找出最優(yōu)解的性質(zhì),并刻畫其結(jié)構(gòu)特征;

2、遞歸地定義最優(yōu)值;

3、采用自底向上的方式計(jì)算問題的最優(yōu)值;

4、根據(jù)計(jì)算最優(yōu)值時(shí)得到的信息,構(gòu)造最優(yōu)解。

1~3步是動(dòng)態(tài)規(guī)劃算法解決問題的基本步驟,在只需要計(jì)算最優(yōu)值的問題中,完成這三個(gè)基本步驟就可以了。如果問題需要構(gòu)造最優(yōu)解,還要執(zhí)行第4步;此時(shí),在第3步通常需要記錄更多的信息,以便在步驟4中,有足夠的信息快速地構(gòu)造出最優(yōu)解。

下面通過對(duì)具體實(shí)例的分析,幫助大家領(lǐng)會(huì)可用動(dòng)態(tài)規(guī)劃算法求解的問題應(yīng)具有的兩個(gè)性質(zhì)以及動(dòng)態(tài)規(guī)劃算法的設(shè)計(jì)思想。

例:攔截導(dǎo)彈(問題來源:1999年全國(guó)青少年信息學(xué)(計(jì)算機(jī))奧林匹克分區(qū)聯(lián)賽高中組復(fù)賽試題第一題)

某國(guó)為了防御敵國(guó)的導(dǎo)彈襲擊,發(fā)展出一種導(dǎo)彈攔截系統(tǒng)。但是這種導(dǎo)彈攔截系統(tǒng)有一個(gè)缺陷:雖然它的第一發(fā)炮彈能夠到達(dá)任意的高度,但是以后每一發(fā)炮彈都不能高于前一發(fā)的高度。某天,雷達(dá)捕捉到敵國(guó)的導(dǎo)彈來襲。由于該系統(tǒng)還在試用階段,所以只有一套系統(tǒng),因此有可能不能攔截所有的導(dǎo)彈。

輸入導(dǎo)彈依次飛來的高度(雷達(dá)給出的高度數(shù)據(jù)是不大于30000 的正整數(shù)),計(jì)算這套系統(tǒng)最多能攔截多少導(dǎo)彈,并依次輸出被攔截的導(dǎo)彈飛來時(shí)候的高度。

樣例:

INPUT

389 207 155 300 299 170 158 65

OUTPUT

6(最多能攔截的導(dǎo)彈數(shù))

389 300 299 170 158 65

分析:因?yàn)橹挥幸惶讓?dǎo)彈攔截系統(tǒng),并且這套系統(tǒng)除了第一發(fā)炮彈能到達(dá)任意高度外,以后的每一發(fā)炮彈都不能高于前一發(fā)炮彈的高度;所以,被攔截的導(dǎo)彈應(yīng)該按飛來的高度組成一個(gè)非遞增序列。題目要求我們計(jì)算這套系統(tǒng)最多能攔截的導(dǎo)彈數(shù),并依次輸出被攔截導(dǎo)彈的高度,實(shí)際上就是要求我們?cè)趯?dǎo)彈依次飛來的高度序列中尋找一個(gè)最長(zhǎng)非遞增子序列。

設(shè)X={x1,x2,…,xn}為依次飛來的導(dǎo)彈序列,Y={y1,y2,…,yk}為問題的最優(yōu)解(即X的最長(zhǎng)非遞增子序列),s為問題的狀態(tài)(表示導(dǎo)彈攔截系統(tǒng)當(dāng)前發(fā)送炮彈能夠到達(dá)的最大高度,初值為s=∞——第一發(fā)炮彈能夠到達(dá)任意的高度)。如果y1= x1,即飛來的第一枚導(dǎo)彈被成功攔截。那么,根據(jù)題意“每一發(fā)炮彈都不能高于前一發(fā)的高度”,問題的狀態(tài)將由s=∞變成s≤x1(x1為第一枚導(dǎo)彈的高度);在當(dāng)前狀態(tài)下,序列Y1={y2,…,yk}也應(yīng)該是序列X1={x2,…,xn}的最長(zhǎng)非遞增子序列(大家用反證法很容易證明)。也就是說,在當(dāng)前狀態(tài)s≤x1下,問題的最優(yōu)解Y所包含的子問題(序列X1)的解(序列Y1)也是最優(yōu)的。這就是攔截導(dǎo)彈問題的最優(yōu)子結(jié)構(gòu)性質(zhì)。

設(shè)D(i) 為第i枚導(dǎo)彈被攔截之后,這套系統(tǒng)最多還能攔截的導(dǎo)彈數(shù)(包含被攔截的第i枚)。我們可以設(shè)想,當(dāng)系統(tǒng)攔截了第k枚導(dǎo)彈xk,而xk又是序列X={x1, x2,…,xn}中的最小值,即第k枚導(dǎo)彈為所有飛來的導(dǎo)彈中高度最低的,則有D(k)=1;當(dāng)系統(tǒng)攔截了最后一枚導(dǎo)彈xn,那么,系統(tǒng)最多也只能攔截這一枚導(dǎo)彈了,即D(n)=1;其它情況下,也應(yīng)該有D(i)≥1。根據(jù)以上分析,可歸納出問題的動(dòng)態(tài)規(guī)劃遞歸方程為:

假設(shè)系統(tǒng)最多能攔截的導(dǎo)彈數(shù)為dmax(即問題的最優(yōu)值),則

dmax (i為被系統(tǒng)攔截的第一枚導(dǎo)彈的順序號(hào))

所以,要計(jì)算問題的最優(yōu)值dmax,需要分別計(jì)算出D(1)、D(2)、……D(n)的值,然后將它們進(jìn)行比較,找出其中的最大值。根據(jù)上面分析出來的遞歸方程,我們完全可以設(shè)計(jì)一個(gè)遞歸函數(shù),采用自頂向下的方法計(jì)算D(i)的值。然后,對(duì)i從1到n分別調(diào)用這個(gè)遞歸函數(shù),就可以計(jì)算出D(1)、D (2)、……D(n)。但這樣將會(huì)有大量的子問題被重復(fù)計(jì)算。比如在調(diào)用遞歸函數(shù)計(jì)算D(1)的時(shí)候,可能需要先計(jì)算D(5)的值;之后在分別調(diào)用遞歸函數(shù)計(jì)算D(2)、D(3)、D(4)的時(shí)候,都有可能需要先計(jì)算D(5)的值。如此一來,在整個(gè)問題的求解過程中,D(5)可能會(huì)被重復(fù)計(jì)算很多次,從而造成了冗余,降低了程序的效率。

其實(shí),通過以上分析,我們已經(jīng)知道:D(n)=1。如果將n作為階段對(duì)問題進(jìn)行劃分,根據(jù)問題的動(dòng)態(tài)規(guī)劃遞歸方程,我們可以采用自底向上的方法依次計(jì)算出D(n-1)、D(n-2)、……D(1)的值。這樣,每個(gè)D(i)的值只計(jì)算一次,并在計(jì)算的同時(shí)把計(jì)算結(jié)果保存下來,從而避免了有些子問題被重復(fù)計(jì)算的情況發(fā)生,提高了程序的效率。算法代碼如下:

for i=1 to n

D(i)=1

next i

for i=n-1 to 1 step -1

for j=i+1 to n

 if x(j)<=x(i) and D(i)<D(j)+1 then

D(i)=D(j)+1

endif

next j

next i

dmax=0:xh=1

rem dmax用來保存問題的最優(yōu)值(系統(tǒng)最多能攔截的導(dǎo)彈數(shù));xh用來保存第一枚被攔截的導(dǎo)彈的順序號(hào),以便后面構(gòu)造最優(yōu)解

for i=1 to n

if D(i)>dmax then

 dmax=D(i)

 xh=i

endif

next i

我們?cè)谟?jì)算最優(yōu)值時(shí)保存了被攔截的第一枚導(dǎo)彈的順序號(hào)xh。接下來通過這個(gè)信息構(gòu)造問題的最優(yōu)解(由所有被攔截的導(dǎo)彈的高度組成的非遞增序列)。算法代碼如下:

print x(xh)

for i=xh+1 to n

if x(i)<=x(i-1) then

 print x(i)

endif

next i

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容