Contents
閉路の検出
無向グラフ
閉路が存在するか自体はトポロジカルソートによって判別可能です。
有向グラフ
具体的な閉路のパスを1つ取得方法としては、DFSが挙げられます。
struct Edge {
int to;
Edge(int _to) : to(_to) {
}
};
using Graph = vector<vector<Edge>>;
int cycle_node = -1; // 閉路上に存在するノードのid
vb seen; // 探索済みフラグ
vb finished; // 探索済みで、絶対にサイクルがないノード
vi history;
void dfs(const Graph& g, int idx) {
if (finished[idx]) {
return;
}
history.push_back(idx);
// 探索終了していないけど訪問済みなノードに到達
if (seen[idx]) {
// それは閉路である
cycle_node = idx;
return;
}
seen[idx] = true;
for (const auto& e : g[idx]) {
if (finished[e.to])
continue;
dfs(g, e.to);
if (cycle_node != -1)
return;
}
finished[idx] = true;
history.pop_back();
}
// 閉路のパス
// 戻り値: 0→閉路なし 1→閉路あり
// cycle: 閉路のpath
int find_cycle(const Graph& g, vector<int>& cycle) {
ll n = g.size();
// init
cycle_node = -1;
seen.assign(n, false);
finished.assign(n, false);
cycle.clear();
// 全ての頂点を確認する
rep(i, n) {
dfs(g, i);
// サイクルが見つかった時点でループを抜ける
if (cycle_node != -1) {
break;
}
}
if (cycle_node == -1) {
return 0;
}
// historyの始めにあるサイクルと無関係なデータを削除
cycle.push_back(cycle_node);
for (auto it = history.rbegin() + 1; it != history.rend(); it++) {
if (*it == cycle[0]) {
break;
}
cycle.push_back(*it);
}
reverse(all(cycle));
return 1;
}
関連問題
- Pure (ABC142)