概念:欧拉通路(又称欧拉路径)、欧拉回路、欧拉图和半欧拉图
定义
- 通过图中所有边恰好一次且行遍所有顶点的通路称为欧拉通路(又称欧拉路径)。
- 通过图中所有边恰好一次且行遍所有顶点的回路称为欧拉回路。
- 具有欧拉回路的图称为欧拉图(Eulerian graph)。
- 具有欧拉通路但不具有欧拉回路的图称为半欧拉图(semi-Eulerian graph)。
- 欧拉回路是欧拉路径,欧拉路径不一定是欧拉回路。
特征
1.在无向图中:
无向图G为欧拉图,当且仅当 G为连通图 且 所有顶点的度为偶数。
无向图G为半欧拉图,当且仅当 G为连通图 且 除了两个顶点的度为奇数之外,其它所有顶点的度为偶数。
2.在有向图中:
有向图G为欧拉图,当且仅当 G为连通图 且 所有顶点的入度等于出度。
有向图G为半欧拉图,当且仅当 G为连通图 且 存在某一顶点的入度比出度大1,还存在另一个顶点的入度比出度小1,而其它所有顶点的入度等于出度。
其中我们可以发现:对于有向图的半欧拉图,它的欧拉路径的起点的度是出度 = 入度+1,终点的度是入度 = 出度+1。
连通图类型 | 欧拉路径的顶点特征 | 欧拉回路的顶点特征 |
---|---|---|
无向图 | 度为奇数的顶点数为 0 或 2 | 度为奇数的顶点数为 0 |
有向图特征 | 起点的入度 - 出度 = -1,终点的入度 - 出度 = 1, 其余顶点的入度 = 出度 | 每个顶点的入度 = 出度 |
Hierholzer 算法
Hierholzer 算法证明了一点:当存在欧拉路径或欧拉回路时,从合理的起点一直执行 DFS 遍历,最后得到的路径一定是欧拉路径或欧拉回路。
Hierholzer 算法用于寻找欧拉路径或欧拉回路(该算法假定图有欧拉路径或欧拉回路),其流程如下:
- 从起点出发,进行深度优先搜索(DFS);
- 每次沿着某条边从某个顶点移动到另外一个顶点的时候,都将这条边标记为已走过;
- 如果遇到阻塞(即当前顶点没有后续邻边或该顶点的邻边都走过),则将当前顶点加入到栈中,并回溯到上一顶点查找其可移动到的顶点。
Hierholzer 算法的重要性质——即它是如何找到欧拉路径或欧拉回路:
- 使用 Hierholzer 算法后,如果该图为欧拉图,则栈底的必定为起点。如果该图为半欧拉图,则栈底的是与起点不同的另外一个奇度数顶点。——实际上栈底存储的都是终点,只是欧拉回路的终点就是起点。
证明:(下面的度数都是指出度 + 入度,下面的当前顶点是指入栈时的顶点)
当顶点入栈时,说明当前顶点没有相邻边。
考虑到从起点出发到当前结点的路径中,除了起点和当前顶点外,其他的顶点都失去了偶数度数。(比如A->B->C->B->D,可以看出,除了起点A和当前顶点D,其它的顶点B和C都是至少一次一进一出,入度和出度失去的个数合起来就是偶数度数,C失去了1个入度和出度,B失去了2个入度和出度)
关键的是:如果起点和当前顶点不同,那么两者都失去了奇数度数。如果起点和当前顶点相同,则起点失去了偶数度数。(途经一顶点时,那个顶点会失去偶数度数。停留在某顶点时,会失去奇数度数,而当前顶点此时的度数为0,所以当前顶点的初始度数为奇数度数)
如果图中包含欧拉回路,意味着所有顶点的初始度数都是偶数。而当前顶点的当前度数为0,表示当前顶点的初始度数必定是奇数,这与欧拉图的特征产生矛盾,因此假设不成立。所以对于欧拉图,当前顶点就是起点。
同样地,对于欧拉路径,当前顶点不可能是起点,否则起点的初始度数就是偶数。而欧拉路径中起点和终点的度数一定是奇数。因此,当前顶点不是起点,但是它的初始度数也是奇数,所以一定是欧拉路径的终点。
- 如果该图为欧拉图或半欧拉图,则栈中的自底到顶的第 N N N 个顶点就是欧拉回路或欧拉路径上的第 N N N 个顶点。
证明:( deg \deg deg 表示度数)
在此只证明栈中相邻顶点在图中也为相邻顶点。因为模拟 Hierholzer 算法过程,可知该算法实际上就是在模拟“一笔画”过程,并且沿着画完的轨迹,从终点开始逆序逐一添加顶点到栈中。
下面主要以 n = 2 n = 2 n=2 的情况为例,后面的情况可以此类推。并且为了不用纠结于区分欧拉回路和欧拉路径,不妨以半欧拉图为例。
假设图中存在相邻的两顶点 V 1 V 2 V_1V_2 V1V2,并且 DFS 的过程中,先访问 V 2 V_2 V2 随后访问了 V 1 V_1 V1,并且 V 1 V_1 V1 成为第一个入栈的顶点。由性质一可知, V 1 V_1 V1 就是欧拉路径上的终点(入度 - 出度 = 1 的顶点为终点)。
根据 Hierholzer 算法可知,在遍历过程中,因为删除了途径的边,所以此时路径中途经的所有顶点(包括起点和终点 V 1 V_1 V1 )的度数都为偶数(0或非0偶数)。那么当然 deg ( V 2 ) \deg( V_2) deg(V2) 也是偶数,接下来就分类讨论。
- 如果 deg ( V 2 ) = 0 \deg( V_2) = 0 deg(V2)=0 ,也就是说当前顶点 V 2 V_2 V2 成为第二个入栈的顶点,那么 n = 2 n = 2 n=2 的情况就证毕了。
- 如果 deg ( V 2 ) > 0 \deg( V_2) > 0 deg(V2)>0 (即不为 0 的偶数),那么考虑当前包含 V 2 V_2 V2 的子图 G G G ,显然 G G G 是一个欧拉图,那么当前以 V 2 V_2 V2 为起点继续实施 Hierholzer 算法遍历剩下的相邻边,根据性质一, V 2 V_2 V2 将会是 G G G 中第一个入栈的顶点。也就是, V 2 V_2 V2 是原图中第二个入栈的顶点。
对于第二种情况我们来举例讨论下:
假设 JFK 先前往 KUL,即 JFK->KUL,可以看出 deg ( J F K ) > 0 \deg(JFK) > 0 deg(JFK)>0 且是偶数,此时我们考虑当前包含 J F K JFK JFK 的子图,很明显这是一个欧拉图,那么由其定义我们可以知道,该子图第一个入栈的一定是 J F K JFK JFK。所以 J F K JFK JFK 是原图中紧接着 K U L KUL KUL 入栈的第二个顶点。
综上所述,以此类推, V n − 1 V_{n-1} Vn−1 入栈前最后接触过的 V n V_n Vn 将会是第 n n n 个入栈的顶点,再结合直观理解, V n V_n Vn 就是路径上的第 n n n 个顶点。