Euler Circuit / Path (Hierholzer)

O(n + m)

Walk that uses every EDGE exactly once (contrast Hamiltonian: every vertex, which is NP-hard). A circuit exists in an undirected graph iff every vertex has even degree and all edges sit in one component; a path allows exactly two odd-degree vertices (start and end). Hierholzer builds it in linear time; the per-vertex ptr is what keeps it linear, never rescanning used edges. Both impossibility conditions surface as the two failure returns.

// use it on

CSES: Mail Delivery

Print an Eulerian circuit from post office 1, or IMPOSSIBLE. The template's two failure returns (odd degree, disconnected edges) are exactly the IMPOSSIBLE cases.

// the code

// Eulerian circuit in an undirected graph; edges as {a, b} pairs.
// Returns the vertex sequence (m+1 long), or {} if none exists.
vector<int> euler_circuit(int n, vector<array<int, 2>>& edges, int start = 0) {
    vector<vector<pair<int, int>>> adj(n);  // (neighbor, edge id)
    for (int i = 0; i < (int)edges.size(); i++) {
        adj[edges[i][0]].push_back({edges[i][1], i});
        adj[edges[i][1]].push_back({edges[i][0], i});
    }
    for (int v = 0; v < n; v++)
        if (adj[v].size() % 2) return {};  // odd degree: no circuit
    vector<int> ptr(n, 0), path, st = {start};
    vector<bool> used(edges.size(), false);
    while (!st.empty()) {
        int v = st.back();
        while (ptr[v] < (int)adj[v].size() && used[adj[v][ptr[v]].second]) ptr[v]++;
        if (ptr[v] == (int)adj[v].size()) {
            path.push_back(v);
            st.pop_back();
        } else {
            auto [to, id] = adj[v][ptr[v]];
            used[id] = true;
            st.push_back(to);
        }
    }
    if (path.size() != edges.size() + 1) return {};  // edges disconnected
    return path;
}
// Euler PATH instead: exactly two odd-degree vertices; start at one of them.
// Directed version: need indegree == outdegree everywhere (for a path: one
// vertex with out-in = 1 as start, one with in-out = 1 as end).