1 基本概念
1.1 欧拉路径和欧拉回路
欧拉路径:欧拉路是指从图中任意一个点开始到图中任意一个点结束
的路径,并且图中每条边
通过的且只通过一次
。
欧拉回路:欧拉回路是指起点和终点相同
的欧拉路。
注意:如果欧拉回路,那么一定存在欧拉路径
注意: 是
每条边
被访问一次
,节点
可能会被访问两次。
充分必要条件:
对于无向图
,所有边都是连通的
(1)存在欧拉路径的充分必要条件:
- 度数为奇数的点只能是0个或者2个
(2)存在欧拉回路的充分必要条件:
- 度数为奇数的只能是0个
对于有向图
,所有边都是连通的
(1)存在欧拉路径的充分必要条件:
- 要么所有点的出度均等于入度。
- 要么除了两个点之外,其余所有点的出度等于入度,剩余的两个点:一个满足出度比入度多1(起点),另一个满足入度比出度多1(终点)。
(2)存在欧拉回路的充分必要条件:
- 所有点的出度均等于入度
2 欧拉路径判定算法
2.1 Fleury(弗罗莱) 算法
Fleury算法用来判断图是否是欧拉路径或欧拉回路的算法。
使用如下的欧拉图,了解Fleury算法的主要步骤。
- 选节点1为起点,并将该起点加入路径中。Fleury算法选择
栈
存储欧拉路径。
- 从起点开始,一路DFS试着走出一条通路。方法是找与此节点相邻的节点。
如果只有一个节点,则将这个点直接加入路径中。
如果有多个相邻节点,则选择其中一条边,把相邻节点加入路径后,且删除这一条边。
如果没有邻接节点,则从路径中弹出
。
节点5和节点2都与1相邻,可以选择向5方向,也可以选择2方向。这里选择2方向,把节点2放入路径,然后置1-2这条边为删除状态。如此这般,一路经过3、4、5节点后回到1号节点。下图中标记为红色的边表示已经访问或被删除。
- 重新回到节点1,此时不再存在与节点1邻接的节点,从路径中弹也,依次可弹出5、4、3。直到碰到2号节点。
- 因为存在与2号节点邻接的节点,再次以2号节点为始点,使用DFS开路。一路上遇到6、7,且再次回到2号节点。
- 2号节点不存在与之邻接的节点,出栈。同理,7、6依次出栈。
小结:
当有与当前节点邻接的节点时,一路DFS,直到没有邻接的尽头。些时,一轮DFS算法结束,从路径中依次弹出没有邻接节点的节点,直到遇到还有邻接节点的节点,新一轮的DFS重新开始。直到所有节点邻接的边全部访问完毕。
编码实现:
#include <iostream>
#include <math.h>
#include <algorithm>
#include <cstring>
#include <stack>
#define INF 100000
using namespace std;
int graph[100][100];
int n,m;
stack<int> sta;
void read() {
for(int i = 0; i < m; i++) {
int f,t;
cin >> f >> t;
graph[f][t] = 1;
graph[t][f] = 1;
}
}
void dfs(int u) {
sta.push(u);
for(int i = 1; i <= n; i++) {
if(graph[i][u] > 0) {
//标记为删除
graph[u][i] = 0;
graph[i