欧拉回路

本文详细介绍了欧拉回路的概念,包括无向图和有向图的欧拉路径和回路的充分必要条件。文章通过算法分析,提供了解决欧拉回路问题的模板,并给出了多个典型例题,如单词游戏、欧拉回路记录边和点的情景等,结合ACwing平台的题目进行了解析和解题思路的分享。
摘要由CSDN通过智能技术生成

欧拉回路

1.算法分析

几个概念:

1.欧拉路:

给定一张无向图,若存在一条从节点S到节点T的路径,恰好不重不漏地经过每条边一次(可以重复经过图中的节点),则称该路径为S到T的欧拉路

2.欧拉回路:

若存在一条从S出发的路径,恰好不重不漏地经过每条边一次(可以重复经过图中的节点),最终回到起点S,则称该路径为欧拉回路

3.欧拉图:

存在欧拉回路的无向图称为欧拉图

结论:

1.对于无向图,所有边都是连通的

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

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

2.对于有向图,所有边都是连通的

(1) 存在欧拉路径的充分必要条件: 要么所有点出度均等于入度(欧拉回路情况);要么除了两个点之外,其余点的出度等于入度,剩余的两个点:一个满足出度比入度多1(起点),另一个满足入度比出度多1(终点)

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

性质:

1.按照如下算法求出来的欧拉回路是逆序的,即:从终点->起点的 欧拉回路

2.对于欧拉路而言,最先搜索的点会出现在搜索序列seq(栈的)的结尾(靠近栈顶的位置),所以如果想要得到一个字典序最小的欧拉路,只需要将seq倒置一下即可。

2.模板

2.1 记录点的情形

void dfs(int x)
    对于从x出发的每条边(x, y)
        如果该边没有被访问过
            把这条边删去
            dfs(y)
    把x入栈

main()
    dfs(1)
    倒序输出栈中所有的节点

2.2 记录边的情形

void dfs(int x)
    对于从x出发的每条边i(x, y)
        如果该边没有被访问过
            把这条边删去
            dfs(y)
            把边i入栈

main()
    dfs(1)
    倒序输出栈中所有的边

3.典型例题

3.1 欧拉回路判定

acwing1185单词游戏

**题意: ** 有 N 个盘子,每个盘子上写着一个仅由小写字母组成的英文单词。你需要给这些盘子安排一个合适的顺序,使得相邻两个盘子中,前一个盘子上单词的末字母等于后一个盘子上单词的首字母。判断是否能达到这一要求。 1 ≤ N ≤ 1 0 5 1≤N≤10^5 1N105,单词长度均不超过1000

题解: 可以把每个单词的首位字母当成一个点,每个单词当成一条边,这样建图。然后判断每个建立的图是否存在欧拉路。同时还要判断整张图是否连通(可以使用并查集来判断:判断每个点是否最上面的父节点是同一个)

代码:

#include <bits/stdc++.h>

using namespace std;

int n, m, t;
int const N = 30, M = N * N;
char str[1100];  // 记录每个单词
int fa[N];       //
int dout[N], din[N], st[N];

int get(int x) {
   
    if (x == fa[x]) return x;
    return fa[x] = get(fa[x]);
}

int main() {
   
    cin >> t;
    while (t--) {
   
        memset(dout, 0, sizeof dout);
        memset(din, 0, sizeof din);
        memset(st, 0, sizeof st);
        cin >> m;

        // 并查集初始化
        for (int i = 0; i < 26; ++i) fa[i] = i;

        // 建图
        for (int i = 0; i < m; ++i) {
   
            scanf("%s", str);
            int len = strlen(str);
            int a = str[0] - 'a', b = str[len - 1] - 'a';
            st[a] = 1, st[b] = 1;  // 记录是否存在
            dout[a]++, din[b]++;   // 记录出度和入度
            fa[get(a)] = get(b);   // 并查集
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值