POJ 1330 Nearest Common Ancestors(tarjan LCA 算法)
關于LCA和RMQ問題
一、最近公共祖先(Least Common Ancestors) 對于有根樹T的兩個結點u、v,最近公共祖先LCA(T,u,v)表示一個結點x,滿足x是u、v的祖先且x的深度盡可能大。另一種理解方式是把T理解為一個無向無環圖,而LCA(T,u,v)即u到v的最短路上深度最小的點。 這里給出一個LCA的例子: 例一 對于T=<V,E> 則有: LCA(T,5,2)=1 RMQ問題是指:對于長度為n的數列A,回答若干詢問RMQ(A,i,j)(i,j<=n),返回數列A中下標在[i,j]里的最小值下標。這時一個RMQ問題的例子: 例二 對數列:5,8,1,3,6,4,9,5,7 有: RMQ(2,4)=3 RMQ問題與LCA問題的關系緊密,可以相互轉換,相應的求解算法也有異曲同工之妙。 下面給出LCA問題向RMQ問題的轉化方法。 對樹進行深度優先遍歷,每當“進入”或回溯到某個結點時,將這個結點的深度存入數組E最后一位。同時記錄結點i在數組中第一次出現的位置(事實上就是進入結點i時記錄的位置),記做R[i]。如果結點E[i]的深度記做D[i],易見,這時求LCA(T,u,v),就等價于求E[RMQ(D,R[u],R[v])],(R[u]<R[v])。例如,對于第一節的例一,求解步驟如下: 數列E[i]為:1,2,1,3,4,3,5,3,1 于是有: LCA(T,5,2) = E[RMQ(D,R[2],R[5])] = E[RMQ(D,2,7)] = E[3] = 1 易知,轉化后得到的數列長度為樹的結點數的兩倍加一,所以轉化后的RMQ問題與LCA問題的規模同次 |
數據很水,但是算法絕對經典,題目要求兩個節點的最近公共祖先,這個tarjan算法使用了并查集+dfs的操作。這個算法研究了我兩個小時,開始的時候在網上查找資料,寫的都不盡人意,看不明白,后來干脆直接看代碼,模擬了一遍,搞懂了。。。看來計算機的世界,只有代碼才是王道!中間的那個并查集操作的作用,只是將已經查找過的節點捆成一個集合然后再指向一個公共的祖先。另外,如果要查詢LCA(a,b),必須把(a,b)和(b,a)都加入鄰接表。
























































































































































還有就是,如果這個樹的根節點不確定,邊沒有方向可言的話,又應該如何做呢?(找不到根了。。。)
如果要找兩個節點之間的一條通路 又該怎么辦?
看來,這個問題還有繼續研究下去的必要。。。
———————————————————————傳說中的分割線——————————————————————————
指針版:













































































































































































汗,寫了個指針版運行速度居然比vector還慢,太打擊我對指針的信心了。。。可能是數據太弱了吧,指針的優勢沒有發揮出來。。。
——————————————————傳說中的分割線——————————————————————————————————
終于用RMQ過了,起初一直RE,原來是RM Q里面的數組開小了。。。不過感覺時間效率不是很高,110MS,應該是詢問的次數太少的原因吧。
RMQ應付的應該是詢問次數非常巨大的情況。而且它是在線的算法,可以按順序輸出結果,這樣才能AC題目啊。
















































































































































posted on 2009-09-21 22:24 abilitytao 閱讀(3564) 評論(1) 編輯 收藏 引用