TOP > グラフ オイラー路
オイラー路(Eulerian-Trail)
説明
有向/無向グラフが与えられたときに、グラフの全ての辺をちょうど $1$ 回ずつ通る路を求める。
計算量
- $O(E)$
実装例
- eulerian-trail($es$, $s$, $directed$):= 辺集合 $es$ 上で、頂点 $s$ から始まるオイラー路を求める。$directed = false$ のとき無向、$true$ のとき有向グラフとして扱う。
template< typename T >
vector< edge< T > > eulerian_path(Edges< T > es, int s, bool directed) {
int V = 0;
for(auto &e : es) V = max(V, max(e.to, e.src) + 1);
vector< vector< pair< edge< T >, int > > > g(V);
for(auto &e : es) {
int sz_to = (int) g[e.to].size();
g[e.src].emplace_back(e, sz_to);
if(!directed) {
int sz_src = (int) g[e.src].size() - 1;
swap(e.src, e.to);
g[e.src].emplace_back(e, sz_src);
}
}
vector< edge< T > > ord;
stack< pair< int, edge< T > > > st;
st.emplace(s, edge< T >(-1, -1));
while(st.size()) {
int idx = st.top().first;
if(g[idx].empty()) {
ord.emplace_back(st.top().second);
st.pop();
} else {
auto e = g[idx].back();
g[idx].pop_back();
if(e.second == -1) continue;
if(!directed) g[e.first.to][e.second].second = -1;
st.emplace(e.first.to, e.first);
}
}
ord.pop_back();
reverse(begin(ord), end(ord));
if(ord.size() != es.size()) return {};
return ord;
}