zoukankan      html  css  js  c++  java
  • 【图论】欧拉回路和欧拉通路

    定义

    下面讨论的图 (G) 均不存在孤立顶点(度数为0的顶点)。

    欧拉回路和欧拉通路
    通过图中所有边恰好一次的回路称为欧拉回路。
    通过图中所有边恰好一次的通路称为欧拉通路。

    欧拉图和半欧拉图
    具有欧拉回路的无向图或有向图称为欧拉图。
    具有欧拉通路但不具有欧拉回路的无向图或有向图称为半欧拉图。

    若图 (G) 是欧拉图,则它为若干个边不重复的回路的并。
    若图 (G) 是半欧拉图,则它为若干个边不重复的回路和一条简单路径的并。

    欧拉图和半欧拉图判定的充要条件
    对于无向图 (G)(G) 是欧拉图,当且仅当 (G) 是连通的,且没有度数为奇数的顶点。
    对于无向图 (G)(G) 是半欧拉图,当且仅当 (G) 是连通的,且恰好有0个或2个度数为奇数的顶点。
    对于有向图 (G)(G) 是欧拉图,当且仅当 (G) 的所有顶点属于同一个强连通分量,且每个顶点的入度和出度相同。
    对于有向图 (G)(G) 是半欧拉图,当且仅当下列四个条件全部满足:
      若把有向边换成无向边, (G) 是连通的;
      且最多一个顶点的入度和出度差为1;
      且最多一个顶点的出度和入度差为1;
      除上述的两个顶点外,其他所有顶点的入度和出度相同。

    代码

    无向图欧拉回路

    n       顶点数
    m       无向边数
    visv    在dfs1中,顶点i是否被遍历过(用于判断存在欧拉回路)
    vise    在dfs2中,无向边i是否被遍历过(用于构造欧拉回路)
    ans     构造欧拉回路的结果
    
    initialize                  初始化图
    addEdge                     向图中加边
    existEulerianCircuit        判断存在欧拉回路,复杂度O(n)。
    constructEulerianCircuit    构造欧拉回路,复杂度O(n+m)。
    
    struct UndirectGraphEulerianCircuit {
    
        int n, m;
        vector<vector<pii>> G;
    
        vector<bool> visv;
        vector<bool> vise;
        vector<int> ans;
    
        void initialize(int n, int m) {
            this->n = n, this->m = m;
            G.clear();
            G.resize(n + 1);
            visv.clear();
            visv.resize(n + 1);
            vise.clear();
            vise.resize(m + 1);
        }
    
        void addEdge(int u, int v, int eid) {
            G[u].emplace_back(v, eid);
            G[v].emplace_back(u, eid);
        }
    
        void dfs1(int u) {
            visv[u] = 1;
            for (const pii &e : G[u]) {
                int v = e.first;
                if (!visv[v])
                    dfs1(v);
            }
        }
    
        bool existEulerianCircuit() {
            for (int i = 1; i <= n; ++i) {
                if (G[i].size() & 1)
                    return 0;
            }
            int comp = 0;
            for (int i = 1; i <= n; ++i) {
                if (G[i].size() && !visv[i]) {
                    ++comp;
                    if (comp >= 2)
                        return 0;
                    dfs1(i);
                }
            }
            return 1;
        }
    
        void dfs2(int u, int peid) {
            while (G[u].size()) {
                pii e = G[u].back();
                G[u].pop_back();
                int v = e.first, eid = e.second;
                if (vise[eid])
                    continue;
                vise[eid] = 1;
                dfs2(v, eid);
            }
            if (peid != -1)
                ans.emplace_back(peid);
        }
    
        void constructEulerianCircuit() {
            ans.clear();
            for (int i = 1; i <= n; ++i) {
                if (G[i].size()) {
                    dfs2(i, -1);
                    break;
                }
            }
            reverse(ans.begin(), ans.end());
        }
    
    } G;
    

    拓展

    构造欧拉通路:先判断欧拉通路存在。若欧拉回路存在,找出欧拉回路输出。若欧拉通路存在,连接一条附加边使得欧拉回路存在,找出欧拉回路,然后把附加边删除。
    构造字典序最小的欧拉回路:对每个点的出边排序,并且从字典序最小的起点开始,每一步贪心选择。
    构造混合图欧拉回路:转化为网络流问题。

    练习

    CF1361C - Johnny and Megan's Necklace
    CF1038E - Maximum Matching

  • 相关阅读:
    201521123031 《Java程序设计》第14周学习总结
    201521123031 《Java程序设计》第13周学习总结
    软工个人作业5——软件工程总结
    软工网络15个人作业4——alpha阶段个人总结
    软工网络15个人作业3——案例分析
    软件工程网络15结对编程作业
    软工网络15个人阅读作业2——提问题
    软件工程网络15个人阅读作业1(201521123036 曾艺佳)
    Java课程设计
    Java课程设计-学生基本信息管理 201521123036
  • 原文地址:https://www.cnblogs.com/purinliang/p/14335332.html
Copyright © 2011-2022 走看看