今天打 \(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\) 為根的子樹的最大流量,那么轉移方程很好寫。
時間復雜度 \(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)\) 。
我們有換根的方程:
\(f[v]\) 的值就表示樹根從 \(u\) 換成 \(v\) 的結果,時間復雜度 \(O(N)\) 。
我們發現,這種問題的一般特征是,通過一次整體的,固定根的樹形 \(DP\) 對整體進行一個求解,這個過程是自下而上的,再通過自上而下的換根操作,關注將一條邊的端點進行換根的影響,因為已知上面的點在全局的值,除去子樹貢獻,可以方便轉移。
參考文獻
李煜東.《算法競賽進階指南》. 二次掃描與換根法
[HDU2196] Computer
題意
給你一棵 \(n\) 個點的樹,輸出以每個頂點為根節點,到樹上點的邊權和最大,輸出這個最大值。
Solution
初看這道題,可能會像上一道題一樣,考慮換根時除去子樹貢獻,但這題要求取 \(max\) ,而不是求和,不好拆分,這類題,就需要在記錄最大值同時,記錄一個次大值,然后就可以換根轉移了,和求樹的直徑是一樣的,這題所有答案取最大值就是這棵樹的直徑,復雜度 \(O(N)\) 。
設 \(f[i][0]\) 表示點 \(i\) 到以它為根的子樹的最遠點的距離
\(f[i][1]\) 表示點 \(i\) 到以它為根的子樹(並且這個子樹與最遠點所在子樹不相同)的次遠點的距離(一會會用到)
\(f[i][2]\) 表示除去點 \(i\) 的子樹后,點 \(i\) 到離它最遠的點的距離
\(val\) 表示邊權
那么 \(f[v][2]\) 怎么求?(\(u\) 表示 \(v\) 的父親)
\(if(f[v][0] + val[i] == f[u][0])\) \(f[v][2] = f[u][1] + val[i];\)
\(else\) \(f[v][2] = f[u][0] + val[i];\)
\(f[v][2] = max(f[v][2], f[u][2] + val[i]);\)
那么一個點 \(i\) 到它的最遠點的距離即為 \(max(f[i][0],f[i][2])\)