單調佇列是一種嚴格單調的佇列,可以單調遞增,也可以單調遞減。隊首位置儲存的是最優解,第二個位置儲存的是次優解。單調佇列可以有兩個操作:
1、插入乙個新的元素,該元素從隊尾開始向隊首進行搜尋,找到合適的位置插入之,如果該位置原本有元素,則替換它。
2、在過程中從隊首刪除不符合當前要求的元素。
單調佇列實現起來可簡單,可複雜。簡單的乙個陣列,乙個head,乙個tail指標就搞定。複雜的用雙向鍊錶實現。
1、儲存最優解,次優解,ect。記住!只有形如2、利用單調佇列對dp方程進行優化,可將o(n)複雜度降至o(1)。也就是說,將原本會超時的n維dp降優化至n-1維,以求通過。這也是我想記錄的重點
是不是任何dp都可以利用單調佇列進行優化呢?答案是否定的。
dp[i]=(max/min)(f[k])+g[i] (k才能用到單調佇列進行優化。
優化的物件就是f[k]。
輸入乙個長度為n的整數序列,其中有正有負,陣列中乙個或連續的多個整數組成乙個子陣列,求所有子陣列的和的最大值,要求時間複雜度為o(n)。
轉移方程:dp[i]=max(dp[i-1]+data[i],data[i]);
舉例:
輸入:
最大子陣列為:=18;
步驟操作
累加的子陣列和
最大的子陣列和1加1
112加-2-11
3拋棄前面的和-1,加333
4加10
1313
5加-4913
6加716167加2
1818
8加-5
1318
int findgreatestsumofsubarray(int *pdata, int nlength)
g_invalidinput = false;
int ncursum = 0;
int ngreatestsum = 0x80000000;//負無窮
for(int i = 0; i < nlength; ++i)
return ngreatestsum;
}
就是這樣一種方式使得我們原本需要o(n^2^)直接降低成為了線性o(n)。
將物品的數量拆成0、1、2、4……等二的指數,分別計算其價值,當做單獨的物品。因為用這些數可以組合出各種<=m(m為此種物品的數量)的數,也就可以用普通的01揹包狀態轉移方程
dp[i][j] = max
時間複雜度為ο(nwlog(m))(n為物品種數,w為揹包大小,m為此物品數量),是一種比較高效的方法。==優化之後==
時間複雜度為ο(n*w),只是常數可能會稍大。字母含義與上方相同根據上面的式子,每個j值對應的k有m[i] + 1個裡面去找最大的那個,就相當於在乙個區間裡面找乙個最大值,可以考慮用單調佇列來做這個事情,每次維護佇列是單調遞減的,每次取出來佇列頭作為轉移,每次加入的時候,把前面的比它小的就出隊,然後超過m[i]+1的也出隊。
根據上面的式子,發現對於j這個維數來說,如果兩個體積值對於we[i]取餘的值不一樣,是不可能轉移的。這樣的話直接按照mod的這個值來做轉移,因為mod的值是在[0,we[i]-1],後面再列舉k的值。
假設mod = j % we[i],a = j / we[i],那麼j = a * we[i] + mod,可得:
dp[i][j] = max
化簡一下,把a - k 用k來替換就可以得到:
dp[i][j] = max + a * va[i]
這樣掃瞄的時候就是,第一重迴圈是列舉i為n(物品種數),第二重迴圈是列舉的mod從0到we[i]-1,然後第三重迴圈是列舉的餘數為mod的情況下的k值,k值是從0到mod + k * we[i] <= v的對於每乙個k對應乙個這麼大小的揹包,然後找以這個為單調佇列末尾的那個佇列頭的值,完成轉移方程。 單調佇列 優化DP
佇列元素保持單調遞增 減 而保持的方式就是通過插隊,把隊尾破壞了單調性的數全部擠掉,從而使佇列元素保持單調。單調佇列的作用 優化dp。許多單調佇列優化的dp可以使複雜度直接降維,下面就以最簡單的一道題為例 在某兩座城市之間有 n 個烽火台,每個烽火台發出訊號都有一定代價。為了使情報準確地傳遞,在連續...
單調佇列優化dp
形如f i max wi的問題都可以用單調佇列優化。例題 板題 注意乙個地方 求完所有的f後 ans不是f n 而是後面的一段字尾的f 注意字尾的左端點。很顯然是rmq問題 計算字首和sum i 對於固定的右端點 i,我們想讓答案最大等價於max,可以用個單調佇列維護。但是隨便乙個資料結構直接on ...
單調佇列優化專題
poj1821 這題是一道比較典型的佇列優化問題吧,狀態方程如下 dp i j max max,dp i 1 j dp i j 1 第i個人不刷,第i個人刷 第j面牆不刷,列舉所有可能結尾的牆 dp i j 表示前i個人刷前j面牆的最大值,且第j面牆必須刷。這題第一用到了雙端佇列deque,學習了不...