\(\mathtt{dp}\) 由 狀態,階段,決策三部分組成。ide
狀態:描述每一個子問題,而且答案能夠由這些問題組合出來。優化
階段:\(\mathtt{dp}\) 枚舉的 」 大方向 「 ,也就是最外層的循環,保證無後效性的前提,很重要的一部分。排序
決策:也就是狀態由哪幾個前綴狀態轉移得來。隊列
\(\mathtt{Ps:}\)遊戲
附加屬性:除階段之外的全部維度集合,輔助轉移,描述問題。it
最優屬性:也就是 \(\mathtt{dp}\) 裏存的值,也多是計數。class
使用 \(\mathtt{dp}\) 的基本條件:原理
重疊子問題: \(\mathtt{dp}\) 比通常的模擬快的前提,也就是重複的問題只算 1 次。搜索
無後效性:不能有狀態 互相轉移 。循環
最優子結構:當前狀態的最優解能夠由其前綴狀態轉移得來。
不遺漏,不重複 的覆蓋整個問題集合。
\(f(i,j)\) 的附加屬性通常是和其後續狀態 有關聯 的維度。
若是附加屬性 \(j\) 中的一部分能夠由剩下的 推導 出來,那麼這一部分能夠省略。
注意決策當中必要的狀態,不能省略。
最重要的維度,也就是首先枚舉這個維度,再在上面進行轉移,保證了階段無後效性,那麼就不用考慮其餘的維度有沒有後效性了。
轉移,考慮到全部的狀態,不能循環轉移。
通常能夠設 \(f(i,j)\) 表示到了第 \(i\) 個階段,其附加屬性爲 \(j\) 的最優解,從階段 \(k\;(k<i)\) 轉移。
線性 \(\mathtt{dp}\) 通常運用在序列上面。其中的 \(j\) 是與其轉移到的狀態有關係的維度,也就是能夠影響後繼狀態的維度,通常是描述第 \(i\) 個階段最後一個的。
\(\mathtt{P4059}\)
按照末尾空格分類便可。
揹包問題九講 崔添翼
\(\mathtt{Ps:}\)
找到容量,價值,重量,注意它們能夠互換。
\(\mathtt{Cf730J}\)
第 \(\mathtt{1}\) 問能夠用貪心,也能夠用揹包 (畫蛇添足) 。
第 \(\mathtt{2}\) 問能夠將水的容量和瓶子的數量做爲揹包的容量 ,瓶子裏原本最多裝有多少水,注意這時候是要以瓶子的數量爲第 \(\mathtt{1}\) 關鍵字更新。
這時候的揹包不一樣於其餘的,容量有 \(\mathtt{2}\) 個維度,由於只有肯定了 \(\mathtt{2}\) 個維度,才能最優化剩下的維度。
這一點要牢記。
\(\mathtt{Poj1742}\)
若是樸素轉移,須要 \(\mathtt{O(N\sum\limits{A_i})}\)
考慮把 可行性 問題轉化成 最優性 問題。
對於每種硬幣,若是求出現階段要湊成 \(i\) 面值的最小的張數,看是否大於 \(\mathtt{A_i}\) 就行了。
注意若是已經湊好了,那麼就不用轉移了。
此題的啓發:能夠將條件轉換成最優屬性 。
以區間長度做爲階段來轉移,通常從小區間轉移到大區間:
\(f(i,j)=f(i+1,j),f(i,j-1)\)
\(f(i,j)=f(i,k),f(k+1,j)\) 枚舉中轉點 \(k\) 。
其中能夠加入附加屬性。
\(\mathtt{P3147}\)
能夠轉換最優屬性,就是把狀態當中的維度與最優屬性互換。
\(\mathtt{P3205}\)
\(\mathtt{P4302}\)
有些區間 \(\mathtt{dp}\) 能夠用貪心優化:
\(\mathtt{P5851}\)
題解
其中的貪心策略爲:對於每頭牛,能夠假設它只吃 \(\mathtt{1}\) 個派。
如要保證最優:還需假設一個限制條件:每頭牛的 \(l_i\) 和 \(r_i\) 不超過區間 \((i,j)\) 。
\(\mathtt{Ps:}\) 首先處理出初始狀態,也就是沒法從其餘區間轉移的狀態,再從它們轉移到後繼狀態。
一般設 \(f(i,j)\) 表示以 \(i\) 節點爲根的子樹內,附加屬性 \(j\) 的最優解。
若是碰到選取節點的問題,能夠設 \(f(i,j)\) 表示第 \(i\) 個節點選 / 不選的最優解。
\(\mathtt{[POI2001]Dynamite}\)
設 \(f(i)\) 表示走完 \(i\) 的子樹所需的時間以及村民裝遊戲時間較大值的最小值,\(g(i)\) 表示走完 \(i\) 的子樹而且走回 \(i\) 的時間。
若是直接轉移,順序會影響到結果,因此須要貪心。
相鄰交換法:
\(\max\{1+f(i),2+g(i)+1+f(i+1)\}>\max\{1+f(i+1),2+g(i+1)+1+f(i)\}\) 。
化簡,得:
\(g(i)-f(i)>g(i+1)-f(i+1)\) 。
按照這個排序便可。
\(\mathtt{[POI2014]FarmCraft}\)
樹上揹包:
具備依賴性,好比要取 \(son(i)\) 就必需要取 \(\mathtt{i}\) 。
枚舉子樹的容量,以及分配給其兒子節點的數量。
設 \(f(i,j)\) 表示在 \(i\) 的子樹上,分配有 \(j\) 個節點,而且要選子結點,必需要選父親節點,\(v_i\) 表示其價值。
\(f(i,j)=f(i,j-k)+f(son(i),k)\)
其中的 \(j\) 要逆序枚舉,其中的原理和 \(\mathtt{01}\) 揹包是同樣的。
注意有時候 \(k<j\) 由於必需要選取父親節點。
\(\mathtt{P2014}\)
\(\mathtt{P1273}\)
\(\mathtt{Ps:}\)
這裏面的內容在揹包中的 泛化物品 中講到過。
若是轉移集合中的元素大小不超過 \(\mathtt{N}\) 且小於 \(\mathtt{K}\) ,那麼能夠將其壓縮成一個 \(\mathtt{N}\) 位 \(\mathtt{K}\) 進制數。
最多見的就是某個點選 / 不選,標記成 \(\mathtt{0/1}\) 。
\(\mathtt{P3052}\)
設 \(f(s)\) 表示選取集合 \(s\) 最小分組,\(g(s)\) 表示 \(s\) 保證最小分組以後末尾最小的容量。
枚舉最後一個加進來的數,看是否加入便可。
\(\mathtt{Ps:}\) 注意枚舉的順序,可能會漏掉某種狀況。
\(\mathtt{P1879}\)
對於矩陣類的 \(\mathtt{dp}\) 通常能夠考慮按照 行 / 列 枚舉。
以前提到過,附加屬性一定是能對後續狀態有限制做用的。
那麼只有上一行對這一行有限制做用,那麼狀態就顯而易見了。
\(\mathtt{P2915}\)
也叫 二次掃描法 。
求解對於每一個節點的最優解。
通常來講,第 \(\mathtt{1}\) 次計算某一個節點的貢獻,第 \(\mathtt{2}\) 次考慮子樹外 / 全局的貢獻,與父親節點的關係。
\(\mathtt{P3478}\)
\(\mathtt{Cf708C}\)
對於一個狀態轉移方程,能夠將與 前綴狀態 有關的信息提取出來,若是要求最小值 / 最大值,那麼能夠考慮單調隊列。
好比最大子區間,就能夠用單調隊列優化。
「一我的要是比你小,還比你強,那你就永遠打不過他了」——單調隊列
\(\mathtt{P2627}\)
\(\mathtt{P2569}\)
統計數量,保證 不重,不漏 。
\(\mathtt{Cf559C}\)
\(\mathtt{Poj1737}\)
\(\mathtt{P6596}\)
\(\mathtt{Ps:}\) 須要找 \(\mathtt{1}\) 個基準點,圍繞這個基準點進行轉移。
就好比某我的要麼是男生,要麼是女生,能夠以此來進行轉移。
\(\mathtt{Poj1037}\)
此題是個很經典的方法。
如要求排列的第 \(\mathtt{C}\) 個方案的題目,能夠用試填法。
\(\mathtt{P5367}\)
能夠預處理出 \(f(i,j,k)\) 表示 \(i\) 個木板,開頭爲第 \(j\) 小,是上升仍是降低的方案數。
那麼能夠從第 \(\mathtt{1}\) 塊木板開始枚舉,保證不超過 \(\mathtt{C}\) 便可。
通常有 \(\mathtt{2}\) 種模型:
求知足限制條件的第 \(\mathtt{K}\) 小的數,或者在區間 \((i,j)\) 內求出知足限制條件的數的總數。
\(\mathtt{Link:}\)
\(\mathtt{Poj3208}\)
這道題是求第 \(\mathtt{K}\) 小的魔鬼數。
發現求排名的題,跟上面將的題很像。
能夠設 \(f(i,j),\;(j\le3)\) ,表示 \(i\) 位數,最長有 \(j\) 個連續的 \(\mathtt{6}\) 的魔鬼數。
\(\mathtt{Ps:}\) 這種題必定要注意是否有前導 \(\mathtt{0}\) 和是否限制在首位。
擬定一個轉移方程:
\(f(i,0)=9\times (f(i-1,0)+f(i-1,1)+f(i-1,2))\)
\(f(i,1)=f(i-1,0)\)
\(f(i,2)=f(i-1,1)\)
\(f(i,3)=f(i-1,2)+10\times f(i-1,3)\)
發現,對於第 \(\mathtt{1,2,3}\) 條轉移方程,是限制在首位的。
對於第 \(\mathtt{4}\) 條轉移方程,是不限制在首位的。
也是用試填法,從高位往低位試填,由於高溫能夠限制數量。
記錄一個 \(\mathtt{p}\) 表示當前末尾有 \(\mathtt{p}\) 個連續的 \(\mathtt{6}\) ,用來轉移(注意若是 \(\mathtt{p=3}\),那麼後面的 \(\mathtt{p}\) 就不改變了)
當 \(\mathtt{p=3}\) ,能夠從 \(f(i-1,0/1/2/3)\) 轉移,發現覆蓋了所有的狀態 。
當 \(\mathtt{p<3}\) ,就須要注意最後 \(\mathtt{1}\) 爲是否有 \(\mathtt{6}\) ,能夠從 \(f(i-1,3-k-(j=6))\) 轉移。
\(\mathtt{P2602}\)
\(\mathtt{P2657}\)
\(\mathtt{P4317}\)
\(\mathtt{P3413}\)
\(\mathtt{P4172}\)
\(\mathtt{dp}\) 的特色就是重疊子問題,若是沒有重疊子問題,那麼就沒有優化了。
若是套模版,設 \(f(i,sum,num,lim)\) ,若是 \(num\%sum=0\) ,就返回 \(\mathtt{1}\) ,不然返回 \(\mathtt{0}\) 。
可是,這裏有個問題, \(num \le 10^{18}\) ,因此不能將 \(num\) 做爲狀態,也就不能轉移了。
因此,必須將其縮小,根據題目條件,存下 \(sum\) 就能夠了。
可是搜索的過程當中, \(sum\) 是會變化的,因此只能枚舉 \(sum\) ,看最後的 \(sum'=sum\) 且 \(nun\%sum=0\) 便可。
此題給咱們的啓發:若是狀態存不下,考慮將其(縮小)或將其做爲枚舉的部分,不能破壞 \(\mathtt{dp}\) 的特色。
【動態規劃】提升組的DP問候
【動態規劃】普及~省選的dp題
面向tg選手的DP練習題
xzy的樹形dp題單
一個動態更新的洛谷綜合題單