图论:欧拉路(转载)

欧拉路

一、 基本概念

欧拉路指的是:存在这样一种图,可以从其中一点出发,不重复地走完其所有的边。

如果欧拉路的起点与终点相同,则称之为欧拉回路

显而易见,欧拉路存在的充要条件如下:

①图是连通的,若不连通不可能一次性遍历所有边。

对于无向图:有且仅有两个点,与其相连的边数为奇数,其他点相连边数皆为偶数;或所有点皆为偶数边点。对于两个奇数点,一个为起点,一个为终点。起点需要出去,终点需要进入,故其必然与奇数个边相连。

如果存在这样一个欧拉路,其所有的点相连边数都为偶数,那说明它是欧拉回路。

因为此时它的起点即是终点,出去后还会回来,刚好形成偶数边。

对于有向图:除去起点和终点,所有点的出度与入度相等。起点出度比入度大1,终点入度比出度大1。若起点终点出入度也相同,则为欧拉回路。

欧拉路问题也常被称为一笔画问题。

二、求解算法

1.1 DFS遍历寻找欧拉路

设给定一张图,已知这张图是欧拉路,要求输出整条欧拉路。

此时可以采用DFS来遍历整张图,寻找欧拉路。

使用DFS寻找欧拉路的基本思想如下:

DFS寻找到第一个无边可走的节点,则这个节点必定为终点。

接下来由于DFS的递归回溯,会退回终点的上一个节点,继续往下搜索,直到寻找到第二个无边可走的节点,则这个节点必定为欧拉路中终点前最后访问的节点。

于是当通过DFS遍历完整张图后,就可以倒序储存下整个欧拉路。

为了便于理解,我们举个例子来进行讲解:

在上图中,存在一个欧拉路。

假设我们DFS时以1为起点,优先访问编号小的节点。

则我们将访问1-2-3-4-5,直到5节点时,无边可访问,则将5记录进答案中。

接着回溯,继续访问6-7-2-8-4。此时所有边已经全部访问,那就根据DFS的过程将节点一一存储进答案。此时的答案数组为5-4-8-2-7-6-4-3-2-1。我们可以发现,这就是欧拉路遍历节点的逆序过程。将答案数组逆序输出,即可求出欧拉路。

参考代码:

#include<bits/stdc++.h>
using namespace std;
int edge[1000][1000];
//为了方便优先访问编号小的节点,这里使用邻接矩阵来存边
//如果使用vector来存图,那还需要对每个节点连接的边进行排序
int ans[1000000];
int degree[1000];//用于储存每个点的度,以求起点
int p=0;
void dfs(int now)
{
    for(int i=1;i<=1000;i++)//顺序寻找可访问的边,优先找编号小的节点
    {
        if(edge[now][i])//若这条边尚未访问过
        {
            edge[now][i]--;//已访问过的边要删去,防止重复访问
            edge[i][now]--;//有向图的话请删去这一行
            dfs(i);
        }
    }
    ans[++p]=now;//将访问的节点储存进答案数组
    //由于递归的特性,这里储存的是逆序过程
}
int main()
{
    ios::sync_with_stdio(false);
    int n;
    cin>>n;//边的个数
    for(int i=1;i<=n;i++)
    {
        int a,b;
        cin>>a>>b;
        edge[a][b]++;
        edge[b][a]++;//有向图的话删去这行
        degree[a]++,degree[b]++;//两个点的度都+1
    }
    int start=0;
    for(int i=1;i<=1000;i++)
    {
        if(degree[i]%2)//如果找到奇数点
        {
            start=i;//那这个奇数点就作为起点,由于顺序遍历,这个起点编号必定最小
            break;
        }
    }
    if(!start)//如果还没找到奇数点,说明是欧拉回路
    {
        for(int i=1;i<=1000;i++)
            if(degree[i])//寻找最小的有度的点即可
            {
                start=i;
                break;
            }
    }
    dfs(start);//dfs寻找欧拉路
    for(int i=p;i>=1;i--)
        cout<<ans[i];//输出给定的欧拉路
}

需要注意,上面的代码是建立在图为欧拉路的前提上的。

若题目没有说明给的图是欧拉路,那还需要进行两次判断:

判断奇数点的个数是不是0或者2,如果不是,则无解。

判断给定的图是不是连通图,可以用并查集来判断,如果不是连通图,则无解。

关于②,这里有一个比较巧妙的判断方法:DFS过后,将答案序列的长度与边的个数进行对比。在连通图的情况下,求出的欧拉路的边的个数应当等于整个图的边的个数。

则答案序列的长度=其访问过的点的个数=总边数-1。

以上面代码来说明就是 if(p<n+1) 则无解。

1.2 欧拉路相关例题

1.2.1 骑马修栅栏 洛谷 P2731

裸题一道。

1.2.2 无序字母对 洛谷 P1341

本题需要注意点不是整数而是一个个字符,且本题需要判断无解的情况。

若奇数点非0非2,或者不是连通图则无解。

1.2.3 词链 洛谷 P1127

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值