動態規劃 總結

Kai-G發表於2024-08-18

##引言——DP的本質

DAG上的動態規劃與樹形DP這兩個詞看上去很高大上,但實則就是記憶化搜尋,而記憶化搜尋其實就是DP的本質。當選擇一個需要用全域性變數來參與描述狀態的方式時,就只能用常規搜尋。但當狀態可以完全被幾個非全域性引數確定性的描述時,就可以用記憶化搜尋,記憶化搜尋可以透過儲存答案並直接提取來大大減少時間複雜度,可見重複狀態越多、則記憶化搜尋所帶來的最佳化就越大,而當狀態完全不重複時,記憶化搜尋就退化成了最樸素的搜尋,且無法使用全域性變數的限制還憑空增加了思維複雜度,顯然不划算。因此,我們只有會使用有意義的記憶化搜尋,即因重複狀態較多而可以帶來較大最佳化的記憶化搜尋。特別的,我們為這種記憶化搜尋起一個好聽的名字,這便是動態規劃。

動態規劃的核心在於用幾個引數完全且確定地刻畫某一個狀態,然後依照狀態間的關係進行記憶化搜尋,特別的,因為動態規劃的狀態完全有幾個參數列示,DP的狀態因而可以被寫在一個表格、一個長方體、或任何n維體上,且狀態間的關係具有單調性,這使得我們可以按照一個較為簡單的規則而非按照搜尋的自然順序來進行計算,且可以保證雖然並未按搜尋的自然順序來計算,但任何狀態在他被用到之前都一定已經算好了,也就是說保證了結果的不變性。這種簡單的規則通常是按行按列的填表法,或者其他能被幾個迴圈簡單描述的填表法,總之這種簡單的規則太過於普遍的能夠出現,且可以轉遞迴為迴圈省去了棧空間,因而被廣泛應用,甚至倒反天罡讓初學者誤以為這才是DP的自然形態,使得初學者無法意識到DP的本質因而極難真正理解DP。儘管如此,遞推式DP確實好用,因而我們下文在DAG上的DP與樹形DP這兩個傳統記搜領域以外,都將全部採用遞推式DP來分析,不過學習者要始終記得DP的本質及遞推式DP這種方式的本質。

##分類

揹包DP,其實算不上是一種DP,只是為了解決揹包問題而單獨畫出來的一個門類,實則就是用多個引數來刻畫狀態並遞推式地進行狀態轉移。

區間DP,其實也只是一種特殊的二維DP,兩個維度分別表示要描述的區間的左右端點,DP值則是描述該區間某性質的一個量值。

數位DP,也沒什麼新活,無非是將DP的一個維度用於表示正在處理某數字的第幾位.

機率DP,無非是解決機率為題時用幾個引數描述狀態,然後推出了遞推式,便稱為機率DP了,其實也不是什麼新玩意。

狀壓DP,終於有點新活了,當我們面對大量小引數時,比如16個大小為1bit的引數,我們不應該用八個變數來表述這一個引數,因為一個變數(哪怕是bool變數)最小也要佔8bit,這是由計算機的結構決定的。因此如果用變數來表達取值範圍小於8bit的引數時勢必會造成浪費,用於描述1bit的引數顯然會造成巨量浪費,因此啟發我們在一個變數的8bit當做八個小變數的集合,用一個short變數來表述16個0/1狀態引數,從而大量節省空間,反向提取資訊時只要利用位運算即可。注意,狀壓只適用於避免空間浪費的,可以在有大量小引數的情況下最佳化空間複雜度,但對時間複雜度並不起最佳化作用(但也幾乎不會帶來額外的時間複雜度,也就是說對於小於8bit的引數而言,狀壓DP思想帶來的空間最佳化是免費的,不用白不用)

狀態DP、計數DP、插頭DP、動態DP,這些勉強也算是有點新活,但總的來說,DP所要學的理論確實少之又少,真正有用的,是下面這些最佳化思想

##最佳化思想

1.免費額度要利用

當DP函式的取值只有0和1時,或其他取值範圍很小的時候,我們要時刻記住DP的取值實則就是免費贈與我們的一個維度,即二維DP實則可以描述一個三維邏輯空間中的狀態,因為兩個引數加一個DP值正好三維,可二維DP的時間複雜度卻只取決於兩個引數,不取決於DP值。因而DP值可以理解為免費額度,從佔小便宜的角度來想,我們要儘可能的利用免費額度多佔便宜,真要花自己錢的時候則要儘量節省。因此當DP函式的取值只有0和1時,或其他取值範圍很小的時候,我們就要將DP值和某一個取值範圍很大的維度的引數相調換,這樣就幾乎可以減去一個維度的時間複雜度,從而實現類似立方時間複雜度的演算法化簡為平方時間複雜度一類的操作

2.好睏,先寫個總結,以後再補

##總結

可見,DP其實沒那麼多分類,沒那麼多新知識,困難DP其實也不過是利用了更多DP最佳化思想,狀態更難描述罷了,想要學會DP,一是要從本質上理解上述提到的所有理論知識,這是DP的本質,二是要大量做題,真正學會上面那些最佳化思想,並且總結出自己的最佳化思路,如此即可。

相關文章