這篇博客寫的非常不錯,我就是看這個學會的。
第一次寫最近公共祖先問題,用的鄰接表指針。
對於一棵有根樹,就會有父親結點,祖先結點,當然最近公共祖先就是這兩個點所有的祖先結點中深度最大的一個結點。
0
|
1
/ \
2 3
比如說在這裏,如果0爲根的話,那麼1是2和3的父親結點,0是1的父親結點,0和1都是2和3的公共祖先結點,但是1纔是最近的公共祖先結點,或者說1是2和3的所有祖先結點中距離根結點最遠的祖先結點。
在求解最近公共祖先爲問題上,用到的是Tarjan的思想,從根結點開始形成一棵深搜樹,非常好的處理技巧就是在回溯到結點u的時候,u的子樹已經遍歷,這時候才把u結點放入合併集合中,這樣u結點和所有u的子樹中的結點的最近公共祖先就是u了,u和還未遍歷的所有u的兄弟結點及子樹中的最近公共祖先就是u的父親結點。以此類推。。這樣我們在對樹深度遍歷的時候就很自然的將樹中的結點分成若干的集合,兩個集合中的所屬不同集合的任意一對頂點的公共祖先都是相同的,也就是說這兩個集合的最近公共最先只有一個。對於每個集合而言可以用並查集來優化,時間複雜度就大大降低了,爲O(n + q),n爲總結點數,q爲詢問結點對數。
另外Tarjan解法,是一個離線算法,就是說它必須將所有詢問先記錄下來,再一次性的求出每個點對的最近公共祖先,只有這樣纔可以達到降低時間複雜度。另外還有一個在線算法,有待學習,呵呵。。
hdu2586 How far away ?
這道題題意是,給定一棵樹,每條邊都有一定的權值,q次詢問,每次詢問某兩點間的距離。這樣就可以用LCA來解,首先找到u, v 兩點的lca,然後計算一下距離值就可以了。這裏的計算方法是,記下根結點到任意一點的距離dis[],這樣ans = dis[u] + dis[v] - 2 * dis[lca(v, v)]了,這個表達式還是比較容易理解的。。
poj1470 Closest Common Ancestors
這道題和上面那道一樣,很典型的LCA問題,不過讀入有點麻煩,求的是每個點被作爲最近公共祖先的次數,呵呵。。