NOIP OI省選演算法之DP

2022-06-28 02:30:13 字數 2305 閱讀 6639

動態規劃演算法是競賽中最常出現的演算法,常見的型別有:

揹包dp 

樹形dp 

狀壓dp 

數字dp 

斜率優化 

矩陣優化 

決策單調性 

多階段決策過程(multistep decision process)是指這樣一類特殊的活動過程,過程可以按時間順序分解成若干個相互聯絡的階段,在每乙個階段都需要做出決策,全部過程的決策是乙個決策序列。動態規劃(dynamic programming)演算法是解決多階段決策過程最優化問題的一種常用方法,難度比較大,技巧性也很強。

輸入飛彈依次飛來的高度(雷達給出的高度資料是不大於30000 的正整數),計算這套系統最多能攔截多少飛彈,並依次輸出被攔截的飛彈飛來時候的高度。

樣例:input

389 207 155 300 299 170 158 65

output

6(最多能攔截的飛彈數)

389 300 299 170 158 65

分析:因為只有一套飛彈攔截系統,並且這套系統除了第一發炮彈能到達任意高度外,以後的每一發炮彈都不能高於前一發炮彈的高度;所以,被攔截的飛彈應該按飛來的高度組成乙個非遞增序列。題目要求我們計算這套系統最多能攔截的飛彈數,並依次輸出被攔截飛彈的高度,實際上就是要求我們在飛彈依次飛來的高度序列中尋找乙個最長非遞增子串行。

設x=為依次飛來的飛彈序列,y=為問題的最優解(即x的最長非遞增子串行),s為問題的狀態(表示飛彈攔截系統當前傳送炮彈能夠到達的最大高度,初值為s=∞——第一發炮彈能夠到達任意的高度)。如果y1= x1,即飛來的第一枚飛彈被成功攔截。那麼,根據題意「每一發炮彈都不能高於前一發的高度」,問題的狀態將由s=∞變成s≤x1(x1為第一枚飛彈的高度);在當前狀態下,序列y1=也應該是序列x1=的最長非遞增子串行(大家用反證法很容易證明)。也就是說,在當前狀態s≤x1下,問題的最優解y所包含的子問題(序列x1)的解(序列y1)也是最優的。這就是攔截飛彈問題的最優子結構性質。

設d(i) 為第i枚飛彈被攔截之後,這套系統最多還能攔截的飛彈數(包含被攔截的第i枚)。我們可以設想,當系統攔截了第k枚飛彈xk,而xk又是序列x=中的最小值,即第k枚飛彈為所有飛來的飛彈中高度最低的,則有d(k)=1;當系統攔截了最後一枚飛彈xn,那麼,系統最多也只能攔截這一枚飛彈了,即d(n)=1;其它情況下,也應該有d(i)≥1。根據以上分析,可歸納出問題的動態規劃遞迴方程為:

假設系統最多能攔截的飛彈數為dmax(即問題的最優值),則

dmax   (i為被系統攔截的第一枚飛彈的順序號) 

所以,要計算問題的最優值dmax,需要分別計算出d(1)、d(2)、……d(n)的值,然後將它們進行比較,找出其中的最大值。根據上面分析出來的遞迴方程,我們完全可以設計乙個遞迴函式,採用自頂向下的方法計算d(i)的值。然後,對i從1到n分別呼叫這個遞迴函式,就可以計算出d(1)、d (2)、……d(n)。但這樣將會有大量的子問題被重複計算。比如在呼叫遞迴函式計算d(1)的時候,可能需要先計算d(5)的值;之後在分別呼叫遞迴函式計算d(2)、d(3)、d(4)的時候,都有可能需要先計算d(5)的值。如此一來,在整個問題的求解過程中,d(5)可能會被重複計算很多次,從而造成了冗餘,降低了程式的效率。

其實,通過以上分析,我們已經知道:d(n)=1。如果將n作為階段對問題進行劃分,根據問題的動態規劃遞迴方程,我們可以採用自底向上的方法依次計算出d(n-1)、d(n-2)、……d(1)的值。這樣,每個d(i)的值只計算一次,並在計算的同時把計算結果儲存下來,從而避免了有些子問題被重複計算的情況發生,提高了程式的效率。演算法**如下:

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)dmax then

dmax=d(i)

xh=i

endif

next i

我們在計算最優值時儲存了被攔截的第一枚飛彈的順序號xh。接下來通過這個資訊構造問題的最優解(由所有被攔截的飛彈的高度組成的非遞增序列)。演算法**如下:

print x(xh)

for i=xh+1 to n

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

print x(i)

endif

next i

結束語:

動態規劃演算法和貪婪演算法都是構造最優解的常用方法。動態規劃演算法沒有乙個固定的解題模式,技巧性很強。可以說,動態規劃演算法在實際生活中的每一次應用都是一種創造。大家要多練習,多實踐,從實踐中領會動態規劃演算法的精髓,不斷提高自己的應用能力

省選演算法匯集

陣列 鍊錶,雙向鍊錶 佇列,單調佇列,雙端佇列 棧,單調棧 堆並查集與帶權並查集 hash 表 自然溢位 雙hash 樹狀陣列 線段樹,線段樹合併 平衡樹treap 隨機平衡二叉樹 splay 伸展樹 scapegoat tree 替罪羊樹 塊狀陣列,塊狀鍊錶 5.樹套樹 線段樹套線段樹 線段樹套平...

省選 簡單演算法

這裡是一些簡單的演算法模板,沒有編譯過.編譯過的話會做特殊說明 目錄 1.最近公共祖先 2.cdq分治 1.最近公共祖先 namespace lca void dfs int u,int fa if x y return x for int i log 1 i 0 i if f i x f i y ...

OI省選演算法彙總

簡單列了一點 1.1 基本資料結構 1.陣列 2.鍊錶,雙向鍊錶 3.佇列,單調佇列,雙端佇列 4.棧,單調棧 1.2 中級資料結構 1.堆 2.並查集與帶權並查集 3.hash 表 自然溢位 雙hash 1.3 高階資料結構 1.樹狀陣列 2.線段樹,線段樹合併 3.平衡樹 treap 隨機平衡二...