1. 程式人生 > 實用技巧 >樹形 DP 從入土到入門

樹形 DP 從入土到入門

目錄
emm隨便錯

例題

沒有上司的舞會

沒有上司的舞會
定義 \(f[x][0/1]\) 表示x這個點選或者不選能夠帶來的最大的快樂值。

因為每一個人的頂頭上司肯定不能和他一起選,也就是說,如果當前這個人選了,那麼他的直接下屬不能選,但是當前這個人不選對快樂值沒有影響,也就是。

\[\begin{cases} f_{x, 1} = f_{to, 0} \\ f_{x, 0} = \text{max}(f_{to, 1}, f_{to, 0}) \end{cases} \]

然後題目就做完了,一個 dfs 解決問題

[HAOI2009]毛毛蟲


題面自己看吧,簡化不動...


傳送門
我們令 \(f_x\) 表示以 x 為根的子樹內最大的毛毛蟲的大小,而且 x 為毛毛蟲的頭,那麼 \(f_x\) 的轉移方程就很顯然了。
\(cnt_x\) 為 x 的兒子大小。
\(f_x = \max_{to \in son_x} f_{to} + 1 + \max(0, cnt_{to} - 1)\)

[ZJOI2007]時態同步

傳送門


給你一棵樹,邊有邊權,然後問你每次可以將一條邊的邊權加一,
問你至少多少次操作之後,1 這個根節點到葉子節點的路徑長度都相同。


可以讓所有葉子節點同時發出訊號,然後這些訊號同時到達根節點。於是我們可以自下而上的進行維護,使得每一節點所有子節點的訊號同時到達該節點。

我們從根節點開始搜尋,搜尋到葉子節點,回溯的時候進行維護,先維護節點的所有子節點到該節點最大邊權(邊權為葉子節點到同時到達它所需要時間)。然後維護答案,答案為最大邊權減去所有到子節點的邊權。然後維護父節點的邊權,父節點邊權為該節點子節點的 最大邊權+父節點到該節點的時間。然後就回溯,重複操作,到根節點為止。

換根法

也叫二次掃描法
基本思路是先指定一個根結點,然後第一次dfs求出根節點的權值,然後第二次dfs的時候可以搞一個轉移方程由根結點轉移過去。

STA-Station

傳送門


給定一個 nn 個點的樹,請求出一個結點,使得以這個結點為根時,所有結點的深度之和最大。
一個結點的深度之定義為該節點到根的簡單路徑上邊的數量。


\(dp_i\) 為第 i 個結點作為根節點時的深度之和,我們不妨令根結點為 1,然後進行第一次dfs,求出根結點為 1 時的深度之和,然後考慮如何轉移。

以樣例為例

8
1 4
5 6
4 5
6 7
6 8
2 4
3 4


我們可以知道 \(dp_4\)\(12\) 考慮如何換到5這個結點。

因為換成 5 的時候相當於 5 所在的子樹所有的結點的深度都減一,剩下的結點的深度都加一,所以我們令 \(siz_x\) 記錄 x 這個結點的子樹的大小,\(point\) 為所有子樹的大小,然後\(x, to\) 為 x 結點與 x 結點所到的 to( x 為 to 的父親結點)。
那麼 \(point - siz_{to}\) 為除了以 to 為根的子樹之外的有多少個點。

\[dp_{to}=dp_x+(point-siz_{to}) - siz_{to} \]

Great Cow Gathering G

傳送門


給你一棵樹,邊有邊權,讓你求出一個到其他所有點的路徑和最小的那個點的路徑和。


和上一個題差不多,就是每每條邊有邊權,也就是說我們可以通過讓 siz 陣列維護的值改變一下來 AC 這道題。

考慮 siz 陣列中存貯每個牛棚的以及他的子樹中,一共有多少頭牛,剩下的轉移就和上邊那個題差不多了。

Choosing Capital for Treeland

傳送門


給你一棵樹,但是樹上的邊都是單向邊,問以 i 點為根的時候,為了能夠遍歷到每個點,需要修改多少條邊的方向。


建圖的時候按照雙向邊建圖,正向和反向邊分別標記,然後可以很輕鬆的求出 1 為根時的答案,轉移的時候就判斷 x 與 to 之間連的邊是正向邊還是反向邊就行了。

樹形揹包