前言
想象一下你碰到了哈密顿回路类的问题(NPC问题),但又要在可观的多项式时间内解出。这时,应该怎么破?
欧拉回路(P问题)闪亮登场!!!它只需你巧妙地重新建一下模,就可以
O(n+m)
O
(
n
+
m
)
(n为点数,m为边数)从容解决!
定义
欧拉路径(欧拉通路):通过图中所有边的简单路。(换句话说,每条边都通过且仅通过一次)也叫”一笔画”问题。
欧拉回路:闭合的欧拉路径。(即一个环,保证每条边都通过且仅通过一次)
欧拉图:包含欧拉回路的图。
起源历史
在一个图中求解一条欧拉回路的问题,起源于欧拉提出的、著名的“七桥问题”。详见百度百科。
判定(充要条件)
下列是判定一个图中是否有欧拉回路/欧拉路径的充要条件。
欧拉回路
- 图G是连通的,无孤立点。
- 无向图奇点数为0;有向图每个点的入度必须等于出度。
欧拉路径
- 图G是连通的,无孤立点。
- 无向图奇点数为0或2,并且这两个奇点其中一个为起点另外一个为终点。有向图,可以存在两个点,其入度不等于出度,其中一个入度比出度大1,为路径的起点;另外一个出度比入度大1,为路径的终点。
算法
如果我们判断出(或题目给定)一个图肯定存在欧拉回路,则可以考虑求解一条欧拉回路。
Fleury算法
目前比较通用的应该是Fleury算法。该算法流程如下:
1. 任取G中一个点x
2. 选择一条从点x出发的边i(若i可以不为桥则不应将i选为桥),设i连向点y,删除i,然后:
1)i不为桥,走到点y;
2)i迫不得已必须为桥,走到点y并删去点x(因为删去i后,点x将成为孤立点)。
3. 步骤2无法执行时停止算法
当算法停止时,依次经过的点所得到的简单回路为图G的一条欧拉回路。
圈套圈算法
当然,也有一种看似很暴力的圈套圈算法。
这个算法大概是,从某个点开始走,当走到死胡同时就将当前点压入栈(答案栈)中,直到退到某个点仍然存在出边,然后继续沿着出边走下去。 然后答案即为将节点从栈顶一个一个地弹出(反向输出整个栈)。
分析
先分析一下圈套圈算法。
首先,设起点为x,则如果在走到点v的时候,我们误打误撞又走回了点v(即走了一个包含点v的环,或者说从点v走回了点v),那么这第一次的点v肯定为点x。因为如果为其他点,则从点x走到点v,又从点v走回了点v,那么v的度数为3,v为奇点,不符合判断条件。
那么我们一直回溯,一边回溯一边压栈,回溯到一个点y有出边,我们就继续从点y找环。如果点y找到一个环A,我们又回溯压栈。那么显然
y→x
y
→
x
的路径先被压入栈中,然后是环A,最后是
x→y
x
→
y
的路径。那么我们可以假想,我们从x走到点y的时候,并没有从它走回点x,而是走了一波环A,最后才走回了点x,这样就恰好搞出了一条欧拉回路。
也就是说,我们会找出包含起点x的一个大环,大环中的每一个点都可能带出一个小环,小环中的每一个点又可能带出一个更小的环……以此算法求出的解(那条欧拉回路),我们走大环走到一个点,若它可以带出一个小环,我们就相当于去先搞了那个小环;尔后才回归大环。
根据上述分析,Fleury算法实质上等于圈套圈算法。
设起点为1,上图中的大环为{1,10,8,9,1}。我们在走到10时,10能带出一个小环{10,4,2,3,10},上图变成下图:
显然,此时边
10→8
10
→
8
为桥,因为10能带出一个小环;而囿于有条件:若i可以不为桥则不应将i选为桥,我们会优先去搞10带出来的那个小环。转化为实际步骤即为走边
10→4
10
→
4
或
10→3
10
→
3
。
如果设大环为{x,v1,v2,v3,…,vk,x},我们在走到vi时,显然
x→vi
x
→
v
i
的边都已删除;所以边
vi→vi+1
v
i
→
v
i
+
1
定然是桥。此时,如果vi能够带出一个小环,那么我们肯定会优先去搞那个小环;尔后重新遍历到vi后(从vi走到vi),再走边
vi→vi+1
v
i
→
v
i
+
1
。