首页 > 编程语言 >[算法学习笔记] 欧拉路

[算法学习笔记] 欧拉路

时间:2024-02-03 17:13:13浏览次数:31  
标签:遍历 出度 路径 笔记 vis 算法 回路 欧拉

免责声明:本文定义并不严谨,笔者是从“浅显易懂”的角度出发写本文。若您需要严谨定义请移步至其他学术文章。

基本定义

欧拉路径,即 能不重不漏经过图上所有边的路径。也可以说 “一笔画问题”。特殊地,如果这条路径的起点和终点一致,则这条路径叫做“欧拉回路”。

其他的定义:

  • 欧拉图:具有欧拉回路的图。
  • 半欧拉图:具有欧拉通路但不具有欧拉回路的图。

一条路径是欧拉路(非欧拉回路),则它一定满足 只有一个点的出度比入度多1(该点路径起点),只有一个点的入度比出度多1(该点为路径终点)。 对于欧拉回路,所有点的入度 = 出度。

以上性质推导显然。根据以上性质,我们来求欧拉路径。

求解

判定欧拉路径

求解前,我们一般需要判定图中是否存在欧拉路径。这很简单,依据欧拉路径的定义即可。

对于有向图,存图的时候记录一下每个点的入度和出度。判定 是否只有一个点的出度比入度多1,只有一个点的入度比出度多1。(当然所有点的入度 = 出度也可)。

对于无向图,只有两个点的度为奇数,我们称之为 “奇点”。这两个点分别为起点,终点。

注意到在判定的同时,我们可以得到欧拉路径的起点(如果存在路径)。

求解欧拉路径

欧拉路径的求解这里主要介绍 Hierholzer 算法。 其他算法感兴趣的请移步 OI-Wiki

Hierholzer 算法实质就是 DFS 遍历。遍历前我们需要找到起点。上文已经提到一部分,这里再说明一下。

对于欧拉路径(非回路),我们找到出度比入度多 1 的那个点。对于欧拉回路,任意一个点都可。

找到起点后,我们进行 DFS 遍历。DFS 遍历的时候,每遍历一条边就把它删去,防止重复遍历。

可以证明如果存在欧拉路径,那么无论如何顺序遍历都可以。即欧拉路径不唯一。所以这样 DFS 遍历是正确的。当然有的题目要求输出顺序最小的,这需要特殊处理。

最后输出顺序的时候倒序输出,原因显然。我们进行的是 DFS。这可以用栈实现。

提供 Hierholzer 算法模板,如下:

模板
void dfs(int u)
{
    for(int i = vis[u];i < Edge[u].size();i = vis[u]) // 使用 vector 建图,这里采取了懒惰删除的方法。从vis_u 开始枚举,也就是从0-vis_u-1 的边都被删除了
    {
        vis[u] = i + 1;
        dfs(Edge[u][i]);
    }
    S.push(u);
}

(对于懒惰删除,可以参考 dijkstra 堆优化的处理)

例题

模板 欧拉路径

骑马修栅栏

实际上在求解欧拉路径的时候,邻接矩阵存图更常用,因为它在删边的时候更加方便。

标签:遍历,出度,路径,笔记,vis,算法,回路,欧拉
From: https://www.cnblogs.com/SXqwq/p/18004953

相关文章

  • 基础算法(十一)二维差分---以题为例
    输入一个 n 行 m 列的整数矩阵,再输入 q 个操作,每个操作包含五个整数 x1,y1,x2,y2,c,其中 (x1,y1)和 (x2,y2) 表示一个子矩阵的左上角坐标和右下角坐标。每个操作都要将选中的子矩阵中的每个元素的值加上 c。请你将进行完所有操作后的矩阵输出。输入格式第一行包含整......
  • Pandas库学习笔记(3)---Pandas Series
    PandasSeriesPandasSeries基本操作pandas.SeriesSeries结构如下:pandas.Series(data,index,dtype,copy)构造函数的参数如下-data:数据采用各种形式,例如ndarray,list,常量index:索引值必须是唯一且可哈希的,且长度与数据相同。如果未传递索引,则默认为np.arrange(n)。dt......
  • 代码随想录算法训练营第十一天| 20. 有效的括号 1047. 删除字符串中的所有相邻重复
    20.有效的括号 给定一个只包括 '(',')','{','}','[',']' 的字符串 s ,判断字符串是否有效。有效字符串需满足:左括号必须用相同类型的右括号闭合。左括号必须以正确的顺序闭合。每个右括号都有一个对应的相同类型的左括号。题目链接:20.有效的括号-力扣(LeetCode)思路:只......
  • 2024牛客寒假算法基础集训营1
    题目链接A.因为判断要素较少,直接条件模拟#include<bits/stdc++.h>usingnamespacestd;#defineintlonglongconstintN=2e5+10;voidsolve(){intn;cin>>n;strings;cin>>s;intD=0,F=0,S=0,d=0,f=0,ss=0;for(inti=0;i<s.size();i++){......
  • 算法入门:排序算法
    文章目录1.冒泡排序2.选择排序3.插入排序4.希尔排序5.归并排序6.快速排序7.堆排序 1.冒泡排序思想:比较相邻元素:从数组的第一个元素开始,比较相邻的两个元素,如果它们的顺序不对(比如前面的元素大于后面的元素),则交换它们的位置。一轮遍历:一轮比较和可能的交换后,最......
  • 基础算法(十)差分模板---以题为例
    输入一个长度为 n的整数序列。接下来输入 m个操作,每个操作包含三个整数 l,r,c,表示将序列中 [l,r]之间的每个数加上 c。请你输出进行完所有操作后的序列。输入格式第一行包含两个整数 n 和 m。第二行包含 n 个整数,表示整数序列。接下来 m 行,每行包含三个整数 l,r......
  • Pandas库学习笔记(2)
    Pandas数据结构Pandas有三种常用的数据结构SeriesDataFramePanel这些数据结构建立在Numpy数组之上,这意味着它们运行速度都非常快。Python、Numpy和Pandas对比Pythonlist:Python自带数据类型,主要用一维,功能简单,效率低Dict:Python自带数据类型,多维键值对,效率低Numpy......
  • 云原生学习第2天笔记
    云原生定义云原生(CloudNative)是指基于云环境、可扩展、可靠的应用程序,它利用容器、微服务、自动化部署、弹性伸缩等特性,使应用程序能够快速、可靠地运行在云环境中。云原生优势云原生应用程序具有以下优势:快速部署:通过容器化技术,实现应用程序的快速打包和部署,减少部署时间。可扩展......
  • 抢红包随机金额算法(均衡随机)
    最优算法在文末,欢迎参考。编写抢红包随机算法功能,通常金额是红包支付后立马算好的,而不是抢一个实时随机一个红包金额,避免并发情况下降低性能。需求仿照微信发红包功能,现有n个人抢金额为m的红包,m>=0.01,n>0,m/n不能小于0.01,需保证每个人都能抢到最低为0.01的金额,金额随机,但金额相......
  • 2024年2月笔记:Redis7.2.4版本在Mac电脑的Docker里安装Redis集群
    本文环境:Mac电脑,Brew和Docker都已安装好,Redis版本:7.2.4第1步,验证Docker和Brewdocker--version  //查看docker版本,此处忽略安装Docker步骤brew--version   //查看版本号第2步,创建Redis集群网络dockernetworkcreateredis-cluster-net   //创建一个名......