zoukankan      html  css  js  c++  java
  • 欧拉回路,欧拉路径

    定义:
    欧拉回路:每条边恰好只走一次,并能回到出发点的路径
    欧拉路径:经过每一条边一次,但是不要求回到起始点

    无向图中:

    1、欧拉路径:充要条件是度数为奇数的点的个数为0或2。

    2、欧拉回路:充要条件是全部是偶点

    有向图中:

    1、欧拉路径:起点出度比入度大1,终点入度比出度大1,或者其他点入度初度都相等。

    2、欧拉回路:每个点出度和入度都相等

     两个算法:

    Hierholzer算法自动寻找欧拉回路,在找不到欧拉回路的情况下会找到欧拉路径。前提是得给它指定好起点。

    算法流程(无向图):

    1.判断奇点数。奇点数若为0则任意指定起点,奇点数若为2则指定起点为奇点。

    2.开始递归函数Hierholzer(x):
      循环寻找与x相连的边(x,u):
        删除(x,u)
        删除(u,x)
        Hierholzer(u);
      将x插入答案队列之中

    3.倒序输出答案队列

    其实就是个dfs:

    void dfs(int x){
        rep(i, 1, n)
            if(ma[x][i]) 
                ma[x][i] = ma[i][x] = 0, dfs(i);
        arr[++pos] = x;
    }

    另一种是Fleury(弗罗莱)算法求欧拉路径

    不介绍了,一搜一堆,贴个码。

    void dfs(int x){
        arr[top++] = x;
        rep(i, 1, n){
            if(ma[i][x]){
                ma[i][x]--;
                ma[x][i]--;
                dfs(i);
            }
        }
    }
    
    void fleury(int ss) {
        int brige;
        top = 0;
        arr[top++] = ss; // 将起点放入Euler路径中
        while (top > 0) {
            brige = 1;
            rep(i, 1, n) { // 试图搜索一条边不是割边(桥) 
                if (ma[arr[top-1]][i]) {
                    brige = 0;
                    break;
                }
            }
            if (brige) { // 如果没有点可以扩展,输出并出栈
                ans[++pos] = arr[--top];
            } else { // 否则继续搜索欧拉路径
                dfs(arr[--top]);
            }
        }
    }

    注意事项:有的让按照字典序,注意遍历顺序。有的建出来图是有重边的,注意ma[i][j]表示有连几次。

    问题来了,这俩算法有个锤子不一样,甚至表面上复杂度都是o(m)都一样。我也不知道,反正以后就用前者吧,我没搞懂,看到有人说欧拉回路应用还不深入,所以知识点比较简单。

    洛谷的这个要求字典序。
    #include <bits/stdc++.h>
    #define ll long long
    #define ull unsigned long long
    #define met(a, b) memset(a, b, sizeof(a))
    #define rep(i, a, b) for(int i = a; i <= b; i++)
    #define bep(i, a, b) for(int i = a; i >= b; i--)
    #define pb push_back
    #define mp make_pair
    #define debug cout << "KKK" << endl
    #define ls num*2
    #define rs num*2+1
    #define re return
    using namespace std;
    const ll mod = 1e9 + 7;
    const double PI = acos(-1);
    const ll INF = 2e18+1;
    const int inf = 1e9 + 15;
    const double eps = 1e-7;
    const int maxn = 1e5 + 5;
    int ma[257][257], fa[333], n = 256, du[333];
    string ans;
    int f(int x){
        if(x == fa[x]) return x;
        re fa[x] = f(fa[x]);
    }
    
    void dfs(int x){
        // cout << x << endl;
        rep(i, 1, n){
            if(ma[x][i]){
                ma[x][i] = ma[i][x] = 0;
                dfs(i);
            }
        }
        ans += (char)x;
    }
    
    int main(){
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
        int m; cin >> m;
        string s; rep(i, 1, n) fa[i] = i;
        int flag = 0, num = 0, st = 0;
        rep(i, 1, m){
            cin >> s;
            ma[s[0]][s[1]] = ma[s[1]][s[0]] = 1;
            fa[f(fa[s[0]])] = f(fa[s[1]]);
            du[s[0]]++; du[s[1]]++;
        }
        st = 0;
        rep(i, 1, n){
            if(fa[i] == i && du[i]) flag++;
            if(du[i] % 2 == 1){
                num++;
                if(!st) st = i;
            }
        }
        if(flag != 1 || (num && num != 2)){
            cout << "No Solution" << endl;
            re 0;
        }
        if(!st) rep(i, 1, n) if(du[i]){st = i; break;}
        dfs(st); reverse(ans.begin(), ans.end());
        cout << ans << endl;
        re 0;
    }

    hihoCoder #1181 : 欧拉路·二 有重边

    #include <bits/stdc++.h>
    #define ll long long
    #define ull unsigned long long
    #define met(a, b) memset(a, b, sizeof(a))
    #define rep(i, a, b) for(int i = a; i <= b; i++)
    #define bep(i, a, b) for(int i = a; i >= b; i--)
    #define pb push_back
    #define mp make_pair
    #define debug cout << "KKK" << endl
    #define ls num*2
    #define rs num*2+1
    #define re return
    using namespace std;
    const ll mod = 1e9 + 7;
    const double PI = acos(-1);
    const ll INF = 2e18+1;
    const int inf = 1e9 + 15;
    const double eps = 1e-7;
    const int maxn = 1e5 + 5;
    map<int, int> ma[1005];
    vector<int> v[maxn];
    int n, arr[maxn], ans[maxn], pos, top, du[maxn];
    
    void dfs(int x){
        arr[top++] = x;
        for(auto i: v[x])
            if(ma[x][i] == 1){
                ma[x][i] = 0;
                ma[i][x] = 0;
                dfs(i);
                break;
            }
    }
    
    void fleury(int ss) {
        int brige;
        top = 0;
        arr[top++] = ss; // 将起点放入Euler路径中
        while (top > 0) {
            brige = 1;
            rep(i, 1, n) { // 试图搜索一条边不是割边(桥) 
                if (ma[arr[top-1]][i]) {
                    brige = 0;
                    break;
                }
            }
            if (brige) { // 如果没有点可以扩展,输出并出栈
                ans[++pos] = arr[--top];
            } else { // 否则继续搜索欧拉路径
                dfs(arr[--top]);
            }
        }
    }
    
    int main(){
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
        int m; cin >> n >>  m;
        int flag = 0, num = 0, st = 0;
        rep(i, 1, m){
            int x, y; cin >> x >> y;
            if(ma[x][y] == 0)v[x].pb(y); v[y].pb(x);
            ma[x][y]++; ma[y][x]++;
            du[x]++; du[y]++;
        }
        st = 1;
        rep(i, 1, n){
            if(du[i] % 2 == 1){
                st = i;
                break;
            }
        }
        fleury(st);
        rep(i, 1, pos){
            if(i == pos) cout << ans[i] << endl;
            else cout << ans[i] << ' ';
        }
        re 0;
    }
  • 相关阅读:
    一种新的数据类型Symbol
    var/let/const的区别
    Vue-cli脚手架 安装 并创建项目--命令
    命令
    git版本控制入门--码云
    闲鱼hu超赞,有赞必回,24小时在线!咸鱼互赞超赞留言评
    咸鱼互粉互赞必回 有没有宝贝要的_咸鱼吧
    闲鱼互赞群
    拍摄者能在抖音教学中学会什么
    影响抖音推荐机制的因素和上热门
  • 原文地址:https://www.cnblogs.com/philo-zhou/p/12896589.html
Copyright © 2011-2022 走看看