本文转载自[王陸博主](https://www.cnblogs.com/wkfvawl/p/9626163.html)
1.定义
2. 定理及推论
欧拉通路和欧拉回路的判定是很简单的,请看下面的定理及推论。
无向图G存在欧拉通路的充要条件是:
G为连通图,并且G仅有两个奇度结点(度数为奇数的顶点)或者无奇度结点。
推论1:
1) 当G是仅有两个奇度结点的连通图时,G的欧拉通路必以此两个结点为端点。
2) 当G是无奇度结点的连通图时,G必有欧拉回路。
3) G为欧拉图(存在欧拉回路)的充分必要条件是G为无奇度结点的连通图。
有向图D存在欧拉通路的充要条件是:
D为有向图,D的基图连通,并且所有顶点的出度与入度都相等;或者除两个顶点外,其余顶点的出度与入度都相等,而这两个顶点中一个顶点的出度与入度之差为1,另一个顶点的出度与入度之差为-1。
推论2:
1) 当D除出、入度之差为1,-1的两个顶点之外,其余顶点的出度与入度都相等时,D的有向欧拉通路必以出、入度之差为1的顶点作为始点,以出、入度之差为-1的顶点作为终点。
2) 当D的所有顶点的出、入度都相等时,D中存在有向欧拉回路。
3) 有向图D为有向欧拉图的充分必要条件是D的基图为连通图,并且所有顶点的出、入度都相等。
3.欧拉通路回路存在的判断
根据定理和推论,我们可以很好的找到欧拉通路回路的判断方法,定理和推论是来自离散数学的内容,这里就给出简明的判断方法:
A.判断欧拉通路是否存在的方法
有向图:图连通,有一个顶点出度大入度1,有一个顶点入度大出度1,其余都是出度=入度。
无向图:图连通,只有两个顶点是奇数度,其余都是偶数度的。
B.判断欧拉回路是否存在的方法
有向图:图连通,所有的顶点出度=入度。
无向图:图连通,所有顶点都是偶数度。
4.欧拉回路的应用
A.哥尼斯堡七桥问题
B.一笔画问题
C.旋转鼓轮的设计
5.欧拉回路的求解
A. DFS搜索求解欧拉回路
基本思路:利用欧拉定理判断出一个图存在欧拉回路或欧拉通路后,选择一个正确的起始顶点,用DFS算法遍历所有的边(每一条边只遍历一次),遇到走不通就回退。在搜索前进方向上将遍历过的边按顺序记录下来。这组边的排列就组成了一条欧拉通路或回路。
#include<cstdio> #include<stdio.h> #include<cstring> #include<algorithm> #define MAX 2010 using namespace std; int maps[MAX][MAX]; int in[MAX]; int t[MAX]; int flag; int k; int Max,Min; int DFS(int x) { int i; for(i=Min;i<=Max;i++) { if(maps[x][i])///从任意一个与它相连的点出发 { maps[x][i]--;///删去遍历完的边 maps[i][x]--; DFS(i); } } t[++k]=x;///记录路径,因为是递归所有倒着记 } int main() { int n,i,x,y; Max=-9999; Min=9999; flag=0; scanf("%d",&n); for(i=1;i<=n;i++) { scanf("%d%d",&x,&y); maps[x][y]++; maps[y][x]++; Max=max(x,max(y,Max)); Min=min(x,min(y,Min)); in[x]++; in[y]++; } for(i=Min;i<=Max;i++) { if(in[i]%2)///存在奇度点,说明是欧拉通路 { flag=1; DFS(i); break; } } if(!flag)///全为偶度点,从标号最小的开始找 { DFS(Min); } for(i=k;i>=1;i--) { printf("%d ",t[i]); } return 0; }
B. Fleury(佛罗莱)算法
Fleury算法是对DFS爆搜的一种改进,使用DFS漫不经心的随意走是效率不高的,Fleury是一种有效的算法。
关键是能不走桥就不去走桥,实在无路可走了才去走桥!!!
#include <cstdlib> #include <cstring> #include <cstdio> #include <iostream> #include <algorithm> using namespace std; int ans[200]; int top; int N,M; int mp[200][200]; void dfs(int x) { int i; top++; ans[top]=x; for (i=1; i<=N; i++) { if(mp[x][i]>0) { mp[x][i]=mp[i][x]=0;///删除此边 dfs(i); break; } } }void fleury(int x)
{
int brige,i;
top=1;
ans[top]=x;///将起点放入Euler路径中
while(top>=0)
{
brige=0;
for (i=1; i<=N; i++) /// 试图搜索一条边不是割边(桥)
{
if(mp[ans[top]][i]>0)///存在一条可以扩展的边
{
brige=1;
break;
}
}
if (!brige)/// 如果没有点可以扩展,输出并出栈
{
printf("%d ", ans[top]);
top--;
}
else /// 否则继续搜索欧拉路径
{
top--;///为了回溯
dfs(ans[top+1]);
}
}
}int main()
{
int x,y,deg,num,start,i,j;
scanf("%d%d",&N,&M);
memset(mp,0,sizeof (mp));
for(i=1;i<=M; i++)
{
scanf("%d%d",&x,&y);
mp[x][y]=1;
mp[y][x]=1;
}
num=0;
start=1;///这里初始化为1
for(i=1; i<=N; i++)
{
deg=0;
for(j=1; j<=N; j++)
{
deg+=mp[i][j];
}
if(deg%21)///奇度顶点
{
start=i;
num++;
}
}
if(num0||num==2)
{
fleury(start);
}
else
{
puts("No Euler path");
}
return 0;
}