欧拉回路,欧拉路径

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

无向图中:

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;
}

 

 

posted @ 2020-05-15 21:14  philo_zhou  阅读(640)  评论(0编辑  收藏  举报