ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

欧拉回路

2022-02-08 19:33:00  阅读:220  来源: 互联网

标签:std din dout int st ++ 回路 欧拉


欧拉路径:从某结点出发一笔画成所经过的路线

欧拉回路:在欧拉路径的基础上又回到起点

1、对于无向连通图

(1)存在欧拉路径的充分必要条件是:度数为奇数的点只能有0个或2个

(2)存在欧拉回路的充分必要条件是:不存在度数为奇数的点

2、对于有向连通图

(1)存在欧拉路径的充分必要条件是:除起点和终点外所有点入度均等于出度,同时要么起点出度比入度多1且终点入度比出度多1,要么起点与终点的入度与出度均相等

(2)存在欧拉回路的充分必要条件是:所有点出度均等于入度

求任意欧拉回路,记录并输出边的编号(链式前向星存图)

1184. 欧拉回路 - AcWing题库

#include <bits/stdc++.h>

using ll = long long;
constexpr int N = 1e5 + 5, M = 4e5 + 5;;

int type;
int h[N], e[M], ne[M], idx;
int n, m;
int ans[M];
bool used[M];
int din[N], dout[N];
int cnt;

void add(int a, int b) {
    e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
}

int main () {    
    std::ios::sync_with_stdio(0); 
    std::cin.tie(0);

    memset(h, -1, sizeof h);
    std::cin >> type;
    std::cin >> n >> m;

    for (int i = 0; i < m; i ++) {
        int a, b;
        std::cin >> a >> b;
        add(a, b);
        if (type == 1) {
            add(b, a);
        }
        din[b] ++, dout[a] ++;
    }

    if (type == 1) {
        for (int i = 1; i <= n; i ++) {
            if (din[i] + dout[i] & 1) {
                std::cout << "NO\n";
                return 0;
            }
        }
    } else {
        for (int i = 1; i <= n; i ++) {
            if (din[i] != dout[i]) {
                std::cout << "NO\n";
                return 0;
            }
        }
    }
    std::function<void(int)> dfs = [&](int u) {
        for (int &i = h[u]; ~i; ) {
            if (used[i]) {
                i = ne[i];
                continue;
            }
            used[i] = true;
            if (type == 1) used[i ^ 1] = true;
            int t;
            if (type == 1) {
                t = i / 2 + 1;
                if (i & 1) t = -t;
            } else {
                t = i + 1;
            }
            int j = e[i];
            i = ne[i];
            dfs(j);
            ans[++ cnt] = t;
        }
    };

        for (int i = 1; i <= n; i++) {
            if (~h[i]) {
                dfs(i);
                break;
            }
        }
    
    if (cnt < m) {
        std::cout << "NO\n";
    } else {
        std::cout << "YES\n";
        for (int i = cnt; i >= 1; i --) {
            std::cout << ans[i] << " \n"[i == 1];
        }
    }

    return 0;
}    
/*

*/

记得删完边再遍历

无向图求最小字典序的欧拉路径

#include <bits/stdc++.h>

using ll = long long;

int main () {    
    std::ios::sync_with_stdio(0); std::cin.tie(0);

    int m, n = 500;
    std::cin >> m;
    std::vector g(n, std::vector(n, 0));
    std::vector<int> d(n);
    for (int i = 0; i < m; i ++) {
        int u, v;
        std::cin >> u >> v;
        u --, v --;
        g[u][v] ++, g[v][u] ++;
        d[u] ++, d[v] ++;
    }

    int start = -1;
    for (int i = 0; i < n; i ++) {
        if (start == -1 && d[i]) {
            start = i;
        }
        if (d[i] & 1) {
            start = i;
            break;
        }
    }
    int cnt = 0;
    std::vector<int> ans;
    std::function<void(int)> dfs = [&](int u) {
        for (int i = 0; i < n; i ++) {
            if (g[u][i]) {
                g[u][i] --, g[i][u] --;
                dfs(i);
            }
        }
        ans.push_back(u + 1);
    };

    dfs(start);


    for (int i = ans.size() - 1; ~i; i --) {
        std::cout << ans[i] << "\n";
    }

    return 0;
}       

求有向图字典序最小欧拉路径

P7771 【模板】欧拉路径 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

#include <bits/stdc++.h>

using ll = long long;

int main () {	
	std::ios::sync_with_stdio(0); std::cin.tie(0);

	int n, m;
	std::cin >> n >> m;
	std::vector<int> g[n], din(n), dout(n);
	for (int i = 0; i < m; i ++) {
		int a, b;
		std::cin >> a >> b;
		a --, b --;
		g[a].push_back(b);
		dout[a] ++, din[b] ++;
	}

	for (int i = 0; i < n; i ++) {
		sort(g[i].begin(), g[i].end());
	}

	int start = -1, st = 0, ed = 0;
	bool ok = true;
	for (int i = 0; i < n; i ++) {
		if (din[i] != dout[i]) {
			if (abs(din[i] - dout[i]) > 1) {
				ok = false;
				break;
			} else if (din[i] == dout[i] + 1) {
				ed ++;
			} else {
				st ++, start = i;
			}
		}
	}

	if (st != ed || st > 1 || ed > 1) {
		ok = false;
	}

	if (!ok) {
		std::cout << "No\n";
		return 0;
	}

	std::vector<int> ans;
	std::vector<int> del(n);
	std::function<void(int)> dfs = [&](int u) {
		for (int i = del[u]; i < g[u].size(); i = del[u]) {
			del[u] = i + 1;
			dfs(g[u][i]);
		}
		ans.push_back(u + 1);
	};
	if (start != -1) {
		dfs(start);
	} else {
		for (int i = 0; i < n; i ++) {
			if (g[i].size()) {
				dfs(i);
				break;
			}
		}
	}
	
	std::reverse(ans.begin(), ans.end());
	if (m != ans.size() - 1) {
		std::cout << "No\n";
	} else {
		for (int x : ans) std::cout << x << " "; 
		std::cout << "\n";
	}

	return 0;
}	

有向图判断是否存在欧拉回路

1185. 单词游戏 - AcWing题库

#include <bits/stdc++.h>

using ll = long long;

struct DSU {
    std::vector<int> f, siz;
    DSU(int n) : f(n), siz(n, 1) { iota(f.begin(), f.end(), 0); }
    int leader(int x) {
        while (x != f[x]) x = f[x] = f[f[x]];
        return x;
    }
    bool same(int x, int y) { return leader(x) == leader(y); }
    bool merge(int x, int y) {
        x = leader(x);
        y = leader(y);
        if (x == y) return false;
        siz[x] += siz[y];
        f[y] = x;
        return true;
    }
    int size(int x) { return siz[leader(x)]; }
};

int main () {    
    std::ios::sync_with_stdio(0); std::cin.tie(0);

    int tt; 
    std::cin >> tt;
    while (tt --) {
        int n;
        std::cin >> n;
        std::string s;
        DSU g(30);
        std::vector<bool> st(30);
        std::vector<int> din(30), dout(30);
        int cnt = 0;
        for (int i = 0; i < n; i ++) {
            std::cin >> s;
            int a = s[0] - 'a', b = s.back() - 'a';
            g.merge(a, b);
            dout[a] ++, din[b] ++;
            if (!st[a]) {
                st[a] = true;
                cnt ++;
            }
            if (!st[b]) {
                st[b] = true;
                cnt ++;
            }
        }

        bool ok = true;
        int start = 0, ed = 0;
        for (int i = 0; i < 26; i ++) {
            if (st[i] && g.size(i) != cnt) { //判断连通性
                ok = false;
                break;
            }
            if (st[i]) { //判断是否满足有向图存在欧拉回路的条件
                if (abs(din[i] - dout[i]) > 1) {
                    ok = false;
                } else if (din[i] == dout[i] + 1) {
                    ed ++;
                } else if (din[i] + 1 == dout[i]) {
                    start ++;
                }
            }
        }
        if (start != ed || start > 1 || ed > 1) {
            ok = false;
        }
        if (ok) {
            std::cout << "Ordering is possible.\n";
        } else {
            std::cout << "The door cannot be opened.\n";
        }
    }

    return 0;
}       

有向图按边来寻找字典序最小欧拉环路(暴力写法)

P1127 词链 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

#include <bits/stdc++.h>

using ll = long long;

constexpr int N = 1100;

struct DSU {
    std::vector<int> f, siz;
    DSU(int n) : f(n), siz(n, 1) { iota(f.begin(), f.end(), 0); }
    int leader(int x) {
        while (x != f[x]) x = f[x] = f[f[x]];
        return x;
    }
    bool same(int x, int y) { return leader(x) == leader(y); }
    bool merge(int x, int y) {
        x = leader(x);
        y = leader(y);
        if (x == y) return false;
        siz[x] += siz[y];
        f[y] = x;
        return true;
    }
    int size(int x) { return siz[leader(x)]; }
};

struct node {
	int x, y;
}e[N];

int idx;
void add(int a, int b) {
	e[idx ++] = {a, b};
}

int main () {	
	std::ios::sync_with_stdio(0); std::cin.tie(0);

	int n;
	std::cin >> n;
	std::vector<std::string> g(n);
	std::vector<int> din(30), dout(30);
	for (int i = 0; i < n; i ++) {
		std::cin >> g[i];
	}
	sort(g.begin(), g.end());

	int cnt = 0;
	std::vector<bool> st(30);
	DSU G(30);
	int now = g[0][0] - 'a';
	for (int i = 0; i < n; i ++) {
		int a = g[i].front() - 'a';
		int b = g[i].back() - 'a';
		add(a, b);
		din[b] ++, dout[a] ++;
		G.merge(a, b);
		if (!st[a]) {
			st[a] = true;
			cnt ++;
		}
		if (!st[b]) {
			st[b] = true;
			cnt ++;
		}
	}

	bool ok = true;
	int start = 0, ed = 0;
	for (int i = 0; i < 26; i ++) {
        if (st[i] && G.size(i) != cnt) { 
            ok = false;
            break;
        }
        if (st[i]) { 
            if (abs(din[i] - dout[i]) > 1) {
                ok = false;
            } else if (din[i] == dout[i] + 1) {
                ed ++;
            } else if (din[i] + 1 == dout[i]) {
                start ++, now = i;
            }
        }
    }
    if (start != ed || start > 1 || ed > 1) {
        ok = false;
    }
    if (!ok) {
    	std::cout << "***\n";
    	return 0;
    } 

	std::vector<std::string> ans;
	std::vector<bool> used(n);

	std::function<void(int)> dfs = [&](int now) {
		for (int i = 0; i < idx; i ++) {
			if (!used[i] && g[i][0] - 'a' == now) {
				used[i] = true;
				dfs(g[i].back() - 'a');
				ans.push_back(g[i]);
			}
		}	
	};

	dfs(now);

	for (int i = ans.size() - 1; ~i; i --) {
		std::cout << ans[i] << ".\n"[i == 0]; 
	}

	return 0;
}	

因为这题的结点最多只有26个,所以可以直接给字符串排序一下,然后从前往后找第一个没有打上过标记的字符串

判断欧拉回路是否存在则是用并查集以及欧拉回路的性质来判断

dfs从起点开始,起点要么是字典序最小的字母,要么是奇数度数的点

标签:std,din,dout,int,st,++,回路,欧拉
来源: https://www.cnblogs.com/yramvj/p/15872574.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有