前提
トポロジカルソートの勉強をしています。参照しているサイトは次のものです。
- https://algo-logic.info/topological-sort
- https://qiita.com/drken/items/23a4f604fa3f505dd5ad#4-3-dag-%E3%81%AE%E3%83%88%E3%83%9D%E3%83%AD%E3%82%B8%E3%82%AB%E3%83%AB%E3%82%BD%E3%83%BC%E3%83%88
BFSを使った方は理解できますし、実際に期待通りに動くように見えます。一方で、DFSの方で混乱しています。例えば、1のサイトからコピペしてmain()を追加したコードを書きました。
C++
1#include <bits/stdc++.h> 2using namespace std; 3 4struct Edge { 5 int to; 6}; 7using Graph = vector<vector<Edge>>; 8 9/* topo_sort(G): グラフG をトポロジカルソート 10 返り値: トポロジカルソートされた頂点番号 11 計算量: O(|E|+|V|) 12 */ 13void dfs(const Graph &G, int v, vector<bool> &used, vector<int> &ans) { 14 used[v] = true; 15 for (auto e : G[v]) { 16 if (!used[e.to]) { 17 dfs(G, e.to, used, ans); 18 } 19 } 20 ans.push_back(v); // 帰りがけにpush_back 21} 22vector<int> topo_sort(const Graph &G) { // bfs 23 vector<int> ans; 24 int n = (int)G.size(); 25 vector<bool> used(n, false); 26 for (int v = 0; v < n; v++) { // 未探索の頂点ごとにDFS 27 if (!used[v]) dfs(G, v, used, ans); 28 } 29 reverse(ans.begin(), ans.end()); // 逆向きなのでひっくり返す 30 return ans; 31} 32 33int main() 34{ 35 Graph graph(2); 36 Edge e; 37 38 e.to = 1; 39 graph[0].push_back(e); 40 41 e.to = 0; 42 graph[1].push_back(e); 43 44 auto ts = topo_sort(graph); 45 46 for( auto i : ts ) 47 cout << i << endl; 48}
main()
でしているのはノード0が1を、ノード1が0を参照している単純な循環のあるグラフを作っています。これを実行するとトポロジカルソートに成功します。しかし循環があるので本来は失敗するはずです。BFSを使ったものは失敗します。
コードを読んでみると、ノード0でdfs()
を始めます。ここでused[0] = true
になります。used[1]
はfalse
ですから、DFSでノード1に入ります。
2回目のDFS(ノード1を見ている)では、ノード0へのエッジがありますが、used[0] = true
ですからこれ以上探索はせず、ループを抜けます。その際に、ans.push_back(1)
をしてしまいます。
続けて1回目のDFSに戻り、ループを抜け、ans.push_back(0)
を実行します。結果的にans
には{1, 0}
が入り、一見トポロジカルソートが成功したように見えます。
私はいまトポロジカルソートについて色々調べていて、きちんと理解はしていません。理解するためにコードを読んでいますが、これが正しい実装なのか、私が勘違いしているのかわからず、ここで行き詰まっています。直感では、このコードは誤っています(ループを抜けたところで、ans.push_back(v)
するのはよくないのではという気がします)が、絶対に間違いであると言い切る自身もありません。間違っているとしたら何をするのが正しいのかもよくわかりません。いくつか見たところ、トポロジカルソートの動作を図示しているものもありますが、トポロジカルソートが可能な例ばかりで、循環のあるグラフでDFSを使ったトポロジカルソートを行った解説をまだ見つけていません。
実現したいこと
ここに実現したいことを箇条書きで書いてください。
- このDFS版のトポロジカルソートを正しいものに修正したい
- もし、このコードが正しいのであれば、私が何を間違えているか知りたい
- (この実装が間違っているとして)正しい実装の情報があれば知りたい
他にいくつかトポロジカルソートについての記述を見ましたが、概ね同じ実装をしているようです。
よろしくお願いします。
回答2件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2022/09/24 08:18
2022/09/24 08:28