最初はコンセプトの最新の共通祖先(?最新の共通の祖先が何である)です。
最近の共通の祖先は、このツリー内の2つのノードがある一方で、リングで何の木は、各ノードは、自分の父親や祖先のノードを持っていてはいけない最大の深さの公共の祖先ノード。
換言すれば、このツリー二点共通の祖先ノードに最も近いです。
場合にのみ二点のでLCAプロセスが主に使用される唯一の最短パスがパスを決定しました。
一つは尋ねるかもしれません:どのような彼自身またはかどうか彼の父親ノードの祖先ノードとして、それを?
答えはイエス、それは、人々の考え方の親族によると、シンプルであるあなたの父も、あなたの先祖だった、とLCAも可能先祖ノードとして見られます。
図に示すように、例を与える。ために、4と5の共通の祖先である 2 、5、及び3の共通の祖先である1、2、および1の共通の祖先である1。
これは、基本的な概念の最も最近の共通の祖先である、そしてどのように我々はそれの最も最近の共通の祖先を見つけるために行くのですか?
初心者は通常、最も単純で、粗な方法の1を考える:各お問い合わせは、すべての点を、時間の複雑さがあるO(N * Q) 、それは、明らかであるN-Qと一般的に非常に小さくはありません。
Tarjan / DFS + ST /倍増:LCAは、一般的なアルゴリズムを求めています
2つのアルゴリズムがオンラインアルゴリズムになった後で、非常によく似た時間の複雑さO(LOGN)〜O(nlogn ) の間、私は個人的に理解することはより困難であると思います。
いくつかのセグメントツリーを実行する権利を有することができるが、符号量が大きい場合、時間複雑度が高であるO(N)〜O(nlogn ) との間には、という利点がある単純な、粗。
このブログはTarjanのアルゴリズム(実際には少し難しい...オンライン)を導入する主な理由です。
Tarjan(オフライン)アルゴリズムは何ですか?名前は、意味のすべての尋問時間ソリューションのトラバースですので、その時の複雑さは、O(N + Q) 。
Tarjan利点アルゴリズムは、時間計算量が比較的集中で、比較的安定しているにも理解することは非常に簡単です。
基本的な考え方Tarjanのアルゴリズムに関する次の詳細:
1.必要に応じてルート点は、ルートから始まります。
2.ポイントのU、V、Vのすべての子ノードを横断し、これらの子ノードが訪問されているマーク。
3.子ノードvが存在する場合、そうでない場合は次のステップ、2を返します。
4. UにVをマージします。
5.現在のポイントU点vでコンサルタント関係を検索します。
6. vはすでにあなたがUの最近の共通の祖先を確認することができ、訪問されたとV vが親ノードaにマージされた場合。
使用する必要があるトラバーサルは、DFSの合併については(私は...人々がそれを見て方法を知っていたと信じている)横断するために、最も最適な方法は、2つのノードをマージする互いに素セットを使用することです。
次の擬似コードでは:
1 Tarjan(U)// マージし、検索し、検索機能と機能のセットを見つけるとする 2 { 3。 ための各(U、V) // すべての子へのアクセスは、U Vをノード 4。 { 5。 Tarjan(V); //はダウン続行トラバース 6。 マージ(U、V); // VにUをマージ 7。 アクセスさvの標識; 8 } 。9 用の各(U、E) // アクセス全てのEおよびUが尋問の関係有する 10 { 11 eがある場合訪問; 12である U、(e)は、共通の祖先eが検索され、 13である } 14 }
個人的に私はこれはまだ理解していない多くの人々であると感じたので、私は誰もが見ることのために再びそれをシミュレートするつもりです。
私は一緒にシミュレーションの説明とともに、紙とペンを保持をお勧めします!!
我々はデータノードのセットは、以下のように8つのエッジユニコム9があるとします。
図1--2,1--3,2--4,2--5,3--6,5--7,5--8,7--9即ち木。
私たちは、共通の祖先ポイント9--8,4--6,7--5,5--3を最寄りのセットを見つけたいです。
F []配列チェックされ、父ノードアレイセットを設定し、F初期化[I] = I、VIS []配列への配列がアクセスされ、初期値は0;
ここでは、シミュレーション・プロセスを開始します:
1としたルートノード、検索がダウン 2及び3を見つけ、二人の息子を持っています。
2最初の検索は、二つの二人の息子、4及び図5に示すように、最初の検索4を有する見出さ、4が見つからない子ノードを、それらのポイントとの関係を探しています。
4,6の関係を発見したが、VIS [6] = 0、すなわち、6の上に発見されていない、それは動作しません。
午前4時とは、求めている間には関係が検索した後に戻らないことが見出され、更新VIS [4] = 1。
図4は、探索を完了した表し、更新がF [4] = 2、し続ける5を検索、5 7及び8を発見二人の息子を持っています。
まず、検索7、図7は、子ノード9、発見した検索9を、そのポイントとの関係を探して、何の子ノードを発見しました。
図8及び図9に示すように、関係が見出されたが、VIS [8] = 0、すなわち、それが動作していない、8上に見出されていません。
9とは、検索後に返すように求めの点の間には何の関係が見出されなかった更新をVIS [9] = 1。
表示9已经被搜完,更新f[9]=7,发现7没有没被搜过的子节点了,寻找与其有关系的点;
发现5和7有关系,但是vis[5]=0,所以不操作;
发现没有和7有关系的点了,返回此前一次搜索,更新vis[7]=1;
表示7已经被搜完,更新f[7]=5,继续搜8,发现8没有子节点,则寻找与其有关系的点;
发现9与8有关系,此时vis[9]=1,则他们的最近公共祖先为find(9)=5;
(find(9)的顺序为f[9]=7-->f[7]=5-->f[5]=5 return 5;)
发现没有与8有关系的点了,返回此前一次搜索,更新vis[8]=1;
表示8已经被搜完,更新f[8]=5,发现5没有没搜过的子节点了,寻找与其有关系的点;
发现7和5有关系,此时vis[7]=1,所以他们的最近公共祖先为find(7)=5;
(find(7)的顺序为f[7]=5-->f[5]=5 return 5;)
又发现5和3有关系,但是vis[3]=0,所以不操作,此时5的子节点全部搜完了;
返回此前一次搜索,更新vis[5]=1,表示5已经被搜完,更新f[5]=2;
发现2没有未被搜完的子节点,寻找与其有关系的点;
又发现没有和2有关系的点,则此前一次搜索,更新vis[2]=1;
表示2已经被搜完,更新f[2]=1,继续搜3,发现3有一个子节点6;
搜索6,发现6没有子节点,则寻找与6有关系的点,发现4和6有关系;
此时vis[4]=1,所以它们的最近公共祖先为find(4)=1;
(find(4)的顺序为f[4]=2-->f[2]=2-->f[1]=1 return 1;)
发现没有与6有关系的点了,返回此前一次搜索,更新vis[6]=1,表示6已经被搜完了;
更新f[6]=3,发现3没有没被搜过的子节点了,则寻找与3有关系的点;
发现5和3有关系,此时vis[5]=1,则它们的最近公共祖先为find(5)=1;
(find(5)的顺序为f[5]=2-->f[2]=1-->f[1]=1 return 1;)
发现没有和3有关系的点了,返回此前一次搜索,更新vis[3]=1;
更新f[3]=1,发现1没有被搜过的子节点也没有有关系的点,此时可以退出整个dfs了。
经过这次dfs我们得出了所有的答案,有没有觉得很神奇呢?是否对Tarjan算法有更深层次的理解了呢?
推荐几道LCA的题目
CODEVS 2370 小机房的树 传送门
CODEVS 1036 商务旅行 传送门
METO CODE 223 拉力赛 传送门
HDU 2586 How far way? 传送门
ZOJ 3195 Design the city 传送门
from:https://www.cnblogs.com/JVxie/p/4854719.html
其他优秀文章: