導入
AOVネットワーク
であり描画頂点が有向エッジ<Vと、活動を表すと、I、VとJ > iがアクティブ状態がアクティブでなければならJ表します。これは有向グラフを呼び出したアクティブ頂点表す(頂点のActive)ネットワークを、AOVネットワークをいいます。
AOVネットワークにおいてアクティブVがあれば、私は VなければならJは前に行う、有向エッジ<VあるI、V Jは >、およびV前記Iが VであるJの直接の前駆体、V Jは、 Vである、私が後継者を導きます。このような前駆体および後継関係推移及び抗再帰ネットワークAOVを必要とする、回路表示されない、すなわち、有向リング。したがって、所与のAOVネットワークに、それは最初にそれがリングの存在であるか否かを決定しなければなりません。
トポロジカルソート
すべての先行および後続関係のAOVネットワークを満たすことができるように、リングAOVネットワークトポロジカルソート、線形配列の規則的過程に配置された各頂点によって存在を検出することができます。トポロジカルソートは、すべての頂点が、トポロジのシーケンスに順序付けされAOVネットワークすることができた場合、ネットワークは、AOVリングを持っていない、またはリングにAOVネットワークが存在しなければなりません。順序付けられたシーケンスのAOVネットワークトポロジーの頂点がユニークではありません。トポロジカルソートは、図2に一本の水平ラインの展開のすべてのノードを見ることができ、すべてのエッジは、図の左から右へです。
トポロジカルソートを説明する服のオーダーで、図(A)は、図(B)はトポロジカルソート後に水平線で表示する有向非巡回グラフでそれを示し、他の衣類を着用し、特定の服を着ることができます必要があることを示します。靴下や下着は、結果をソートするに投稿しなければならない人は関係ありません、同じクラスに属します。
アルゴリズムの説明
以下のための非循環有向グラフ
浸透は、(1)ノード0度のためにノード$ $ -1の全てについて、そのノード点を分離することができ、全てのノードをカウントします。
すべてのノードが単離されるまで、(2)を繰り返し(1)、トポロジカルソートが終了します。
(3)0の不在の最後のノード場合、それは環、無溶液があることを示しています。
説明、Aは、ノード0度であると仮定すると、それはノードが直接行うことができない先行ノードがないことを意味し、Aが終了した後、後続のすべてのノードAに対して、ノードが完全な前駆体であります、度$ $ -1。
時間複雑
n個の頂点を持つAOVネットワークは、E、トポロジカルソート処理をエッジ場合、頂点を検索するために必要な時間はゼロであるO(N)です。通常の状況下で、スタックに頂点のそれぞれは、スタック一旦、時間はO(n)のために必要。保存操作の各頂点は1時間eを行いました。そう合計時間複雑度は、O(N + E)です。
結果はユニークなトポロジカル・ソートではないので、対象は通常、いくつかの次出力が必要になります、プライオリティキューを使用する必要があり、ここで辞書最小出力をとるため。
ベクター< INT >ヘッド[ 505 ]、ANS。 INTの N、M、で [ 505 ]。// 入度序列 ボイドtopologicalSorting(){ CIN >> N >> M。 以下のために(int型 i = 0 ; iがm <; iは++ ){ int型C1、C2。 scanf関数(" %dの%のD "、&C1、およびC2)。 ヘッド[C1] .push_back(C2)。 で [C2] ++ ; } PRIORITY_QUEUE < int型、ベクトル< INT >、大きいです<INT >> Q; 以下のために(int型 i = 1 ; iは= N <; iは++ ){ 場合(!における{[i])と q.push(I)。 } } ながら(!q.empty()&& ans.size()< N){ int型 V = q.top()。q.pop(); ans.push_back(V); 以下のために(int型 i = 0 ; iがヘッド[V] .sizeを()<; iは++ ){ に [ヘッド[V] [I]] - 。 もし(!で[ヘッド[V] [I]]) q.push(ヘッド[V] [i])と、 } } 場合(ans.size()== N-){ // トポロジカルソート順序を見つける } 他に{ // 図はループ } }
練習
テンプレートのタイトル
トピックへのリンク:http://acm.hdu.edu.cn/showproblem.php?pid=1285
書式#include <iostreamの> の#include <アルゴリズム> 書式#include <キュー> 書式#include <stdio.hに> する#include <ベクトル> 使用して 名前空間はstdを、 ベクター < INT >ヘッド[ 505 ]。 int型 での [ 505 ]; INT のmain(){ int型N、M。 一方、(CIN >> N >> M){ PRIORITY_QUEUE < int型、ベクトル< INT >、大きな< INT >> Q。 ベクトル < int型 >ANS; 以下のために(int型 i = 0 ; iがm <; iは++ ){ int型C1、C2。 scanf関数(" %dの%のD "、&C1、およびC2)。 ヘッド[C1] .push_back(C2)。 で [C2] ++ ; } ために(int型 i = 1 ; iが<= N; iが++ ){ 場合(!における{[i])と q.push(I)。 } } ながら(!q.empty()){ int型 TEMP = q.top()。q.pop(); ans.push_back(TEMP)。 以下のために(int型 i = 0 ; iは、ヘッドを<TEMP] .sizeを(); iは++ ){ に [ヘッド[TEMP] [I]] - 。 もし(!で[ヘッド[TEMP] [I]]) q.push(ヘッド[TEMP] [i])と、 } } 場合(ans.sizeは()== N){ ため(int型 i = 0 ; iがn <I ++は{) ヘッドを[I + 1 ] .clear(); coutの << ANS [i]は、 もし(!I = N - 1)coutの<< ' ' ; } COUT << ENDL。 } q.emplace()。 ans.clear(); } 戻り 0 。 }
逆トポロジカルソート
トピックへのリンク:http://acm.hdu.edu.cn/showproblem.php?pid=4857
問題の意味:位相関係$は(a、b)は$位相関係は、$ M $を満たしながら、$ Bは$の前になければならない$ A $表す$ Mは$所与$ N $ノード、その結果可能な上面と小さいノード。
一見それはライン上で直接トポロジカル整列を見えますが、例を見て:
$ 6 \ RIGHTARROW 3 \ RIGHTARROW 1 \\ 5 \ RIGHTARROW 4 \ RIGHTARROW 2 $
結果の直接トポロジカルソート:$ 6 \ 3 \ 1 \ 5 \ 4 \ 2 $:$ 5 \ 4 \ 2 \ 6 \ 3 \ 1 $は、私たちは番号を置くことができるので、1がより前面に配置する手配、間違っています(正解)。トポロジカルソートが動作しませんので、直接、なぜそこにそのような状況では、より多くの位相関係のために、当社独自の戦略があるされ、第1ノードのトポロジに小さいシーケンスを削除するために、優先度(例えば第6の接合部よりも小さい第5節などを、我々米国特許第5削除ノード)が、我々はそれを期待優先テールノードトポロジー小さいシーケンスを削除する(例えば米国特許第2ノードのノードより1番小さいように、第1のノード番号を削除しなければなりません)。問題を発見し、我々は最初のリストにリリースすべきかの点を検討し、それが元のトポロジを回すためにあることを、思考を逆転しようとすることができます
$ 1 \ RIGHTARROW 3 \ RIGHTARROW 6 \\ 2 \ RIGHTARROW 4 \ RIGHTARROW 5 $
このようにして、我々は従うの優先順位は、より大きな配列の最初のノードのトポロジー削除結果は、$ 2 \ 4 \ 5 \ 1 \ 3 \ 6 $であるが、非常に適切ではない、まだかのように、1の逆出力にそれを置きます!
書式#include <iostreamの> の#include <アルゴリズム> 書式#include <キュー> 書式#include <stdio.hに> する#include <ベクトル> 使用して 名前空間はstdを、 ベクター < INT >ヘッド[ 30005 ]。 int型 で、[ 30005 ]; INT のmain(){ int型のT。 CIN >> T; 一方、(T-- ){ int型N、M。 CIN >> N >> M。 PRIORITY_QUEUE < 整数 > Q; ベクトル< 整数 > ANS; 以下のために(int型 i = 0 ; iがm <; iは++ ){ int型C1、C2。 scanf関数(" %dの%のD "、&C1、およびC2)。 / * ヘッド[C1] .push_back(C2)。 で[C2] ++; * / ヘッド[C2] .push_back(C1)。 で [C1] ++ ; } のための(int型 i = 1 ; iが<= N; iが++ ){ 場合(!で[I]){ q.push(I)。 } } しばらく(!q.empty()){ int型の TEMP = q.top(); q.pop(); ans.push_back(TEMP)。 以下のために(int型 i = 0 ; iは、ヘッドを<TEMP] .sizeを(); iは++ ){ に [ヘッド[TEMP] [I]] - 。 もし(!で[ヘッド[TEMP] [I]]) q.push(ヘッド[TEMP] [i])と、 } } もし(ans.size()== N){ ため(int型 I = N - 1 ; I> = 0 ; i--){ ヘッド[I + 1]。クリア(); coutの << ANS [i]は、 もし(!I = 0)はcout << ' ' ; } COUT << ENDL。 } q.emplace()。 ans.clear(); } 戻り 0 。 }