1. 程式人生 > 其它 >換根DP學習筆記

換根DP學習筆記

今天打 \(Atcoder\) 時遇到了一道換根 \(DP\) ,發現自己不太會,學習了一下。

一般來說,這類題在做樹形 \(DP\) 時沒有固定的根,可以列舉根然後做 \(N\) 次樹形 \(DP\) ,但複雜度是不太優的,於是有了換根 \(DP\),一般通過兩次對整棵樹的 \(dfs\) 遍歷來求解,複雜度一般是線性的。

還是用例題來直觀講解吧。

[POJ3585] Accumulation Degree

題意

有一個 \(n\) 個結點的樹形水系,每條 \(u->v\) 邊有一個容量 \(C(u,v)\) ,任意一個點都可以作為起點,樹中每個度數為 \(1\) 的結點都可以作為終點,求最大流量。
(其實就是求樹的最大流)
\(n\le10^5\)

Solution

(直接上網路流還是算了吧)
先思考樸素的 \(DP\) 解法,列舉樹根 \(S\) ,對每個 \(S∈ [1,n]\) 做一次樹形 \(DP\) ,設 \(dp[i]\) 表示當前流向以 \(i\) 為根的子樹的最大流量,那麼轉移方程很好寫。

\[dp[i]=\sum_{u∈son[i]} \begin{cases} C(i,u)& \text{deg[u]=1}\\ min(dp[u],C(i,u))& \text{deg[u]> 1} \end{cases}\]

時間複雜度 \(O(N^2)\),過不了本題資料。

發現此題滿足換根的特徵,考慮換根 \(DP\)

\(f[i]\) 表示以 \(i\) 為根流向整顆樹的最大流量,如果我們能線性計算出 \(f\) 陣列,那麼我們的答案只需要取 \(f\) 中的最大值。

任選一個點為根,做一次普通的樹形 \(DP\) 。然後考慮這樣一件事,對於一條邊 \(u->v\) ,現在 \(f[u]\) 的值已經被求出,如何計算出\(f[v]\) 呢?

顯然,已經知道了一個重要的資訊,從 \(u\) 結點流向整顆樹的最大流量,而從 \(u\)\(v\) 的流量(也是到 \(v\) 子樹內所有葉子結點的最大流量和)是 \(min(d[v],C(u,v))\) ,那我們除去這一部分,得到的就是 \(u\)

到除了 \(v\) 所在子樹的流量和,現在我們進行一個神奇的操作,令 \(v\) 為整棵樹的根。

那麼我們就會發現這樣的事情, \(u\) 成了 \(v\) 的一個兒子,且子樹和是 \(f[u]-min(d[v],C(u,v))\) ,這條邊流量仍然是 \(C(u,v)\)

我們有換根的方程:

\[i]=\sum_{u∈son[i]} \begin{cases} C(i,u)& \text{deg[u]=1}\\ min(dp[u],C(i,u))& \text{deg[u]> 1} \end{cases}\]