跳转至

欧拉图

欧拉图判别法

  • 欧拉回路:通过图中每条边恰好一次的回路
  • 欧拉通路:通过图中每条边恰好一次的通路
  • 欧拉图:具有欧拉回路的图
  • 半欧拉图:具有欧拉通路但不具有欧拉回路的图

①无向图是欧拉图当且仅当

  • 非0度顶点是连通的
  • 顶点的度数都是偶数

②无向图是半欧拉图当且仅当

  • 非0度顶点是连通的
  • 恰有2个奇度顶点

③有向图是欧拉图当且仅当

  • 非0度顶点是强连通的
  • 每个顶点的入度等于出度

④有向图是半欧拉图当且仅当

  • 非0度顶点是弱连通的
  • 1个顶点的出度与入度之差为1
  • 1个顶点的入度与出度之差为1
  • 其他顶点的入度和出度相等
例题

P7771 【模板】欧拉路径 - 洛谷

代码
C++
#include <bits/stdc++.h>
using namespace std;
// 2024 OneWan
vector<int> adj[100005];
int cnt[100005], indeg[100005], outdeg[100005];
stack<int> ans;
void Hierholzer(int x) {
    for (int &i = cnt[x] ; i < int(adj[x].size()) ; ) {
        i++;
        Hierholzer(adj[x][i - 1]);
    }
    ans.emplace(x);
}
int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int n, m;
    cin >> n >> m;
    for (int i = 0 ; i < m ; i++) {
        int u, v;
        cin >> u >> v;
        adj[u].emplace_back(v);
        outdeg[u]++;
        indeg[v]++;
    }
    int idx = 1, scnt = 0, ecnt = 0;
    for (int i = 1 ; i <= n ; i++) {
        if (indeg[i] - outdeg[i] == 1) {
            ecnt++;
        } else if (outdeg[i] - indeg[i] == 1) {
            idx = i;
            scnt++;
        } else if (indeg[i] != outdeg[i]) {
            cout << "No\n";
            return 0;
        }
    }

    if (!(ecnt == 0 && scnt == 0) && !(ecnt == 1 && scnt == 1)) {
        cout << "NO\n";
        return 0;
    }
    for (int i = 1 ; i <= n ; i++) {
        if (adj[i].empty()) continue;
        sort(begin(adj[i]), end(adj[i]));
    }
    Hierholzer(idx);
    while (!ans.empty()) {
        cout << ans.top() << " ";
        ans.pop();
    }
    return 0;
}

P2731 [USACO3.3]骑马修栅栏 Riding the Fences - 洛谷

代码
C++
#include <bits/stdc++.h>
using namespace std;
// 2024 OneWan
struct Node {
    int to, rev;
    bool exist;
    Node() = default;
    Node(const int to) : to(to), rev(0), exist(true) {}
    bool operator<(const Node &x) const {
        return to < x.to;
    }
};
stack<int> ans;
vector<Node> adj[1025];
int cnt[1025], deg[1025], top[1025];
void Hierholzer(const int x) {
    for (int &i = cnt[x] ; i < int(adj[x].size()) ; ) {
        if (adj[x][i].exist) {
            Node temp = adj[x][i];
            adj[x][i].exist = false;
            adj[temp.to][temp.rev].exist = false;
            i++;
            Hierholzer(temp.to);
        } else {
            i++;
        }
    }
    ans.emplace(x);
}
int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int n, m;
    n = 500;
    cin >> m;
    for (int i = 0 ; i < m ; i++) {
        int u, v;
        cin >> u >> v;
        adj[u].emplace_back(v);
        adj[v].emplace_back(u);
        deg[u]++;
        deg[v]++;
    }
    int vcnt = 0, idx = 0;
    for (int i = 1 ; i <= n ; i++) {
        if (deg[i] & 1) {
            vcnt++;
            if (idx == 0) idx = i;
        }
    }
    if (vcnt != 0 && vcnt != 2) {
        return 0;
    }
    if (idx == 0) idx = 1;
    for (int i = 1 ; i <= n ; i++) {
        if (adj[i].empty()) continue;
        sort(begin(adj[i]), end(adj[i]));
        for (auto &k : adj[i]) {
            k.rev = top[k.to]++;
        }
    }
    Hierholzer(idx);
    while (!ans.empty()) {
        cout << ans.top() << "\n";
        ans.pop();
    }
    return 0;
}