欧拉回路与欧拉道路
图G的一个回路,若它恰通过G中每条边一次,则称该回路为欧拉(Euler)回路。
如果一个图只是形成一个连通所有节点的链,且每一点只走一次,则成为欧拉道路。
具有欧拉回路或欧拉道路的图称为欧拉图(简称E图)。
有向图的欧拉回路
一个有向图存在欧拉回路的前提条件是这个图是个连通图,其次要求其每个点的入度等于出度,或者其中有一个点的出度比入度大1,另一个点的入度比出度大一这样就存在一条欧拉回路。
如果其每个点的入度等于出度则从任意一点出发,可以走出一条欧拉回路,如果是第二种情况,则必须从出度大于入度 1 的点出发到入度大于出度 1 的点结束,走出一条欧拉道路。
无向图的欧拉回路
跟有向图一样,首先必须连通,其次如果最多只有两个奇点。则满足欧拉回路或欧拉道路,有奇点就从任意一个奇点出发找科形成一条欧拉道路,否则从任意一点出发都能找出欧拉回路。(注意:百度百科上是错的)
如果只是判断一个图是否能够形成欧拉回路的话,就用上面的思路:
首先根据出度跟入度的关系,判断是否满足要求
然后用判断图的连通性可以用并查集或者Dfs如果要求路径的话可以用Dfs
要是需要求出欧拉路径,就用下面这个函数。
下面这个程序,是通过遍历一个图来求其欧拉回路或欧拉道路的。如果需要打印欧拉道路,在主程序中调用,参数必须是道路的起点,另外说明的是,这样打印出来是逆序的,因此在使用的时候,应该用栈压入栈中,还有就是其对无向图和有向图遍历都有用。其实这个算法跟最小生成树prim里面每次求连接上一边最小权值的边算法一样,这个只是那个算法的一个简化。可根据那个进行理解。
#include<iostream>
#include<stack>
const int MAXN=111;
using namespace std;
stack<int>S;
int edge[MAXN][MAXN];
int n,m;
void dfs(int x){
S.push(x);
for(int i=1;i<=n;i++){
if(edge[x][i]>0){
edge[i][x]=edge[x][i]=0;//删除此边
dfs(i);
break;
}
}
}
//Fleury算法的实现
void Fleury(int x){
S.push(x);
while(!S.empty()){
int b=0;
for(int i=1;i<=n;i++){
if(edge[S.top()][i]>0){
b=1;
break;
}
}
if(b==0){
printf("%d",S.top());
S.pop();
}else {
int y=S.top();
S.pop();
dfs(y);//如果有,就dfs
}
}
printf("\n");
}
int main(){
scanf("%d%d",&n,&m); //读入顶点数以及边数
memset(edge,0,sizeof(edge));
int x,y;
for(int i=1;i<=m;i++){
scanf("%d%d",&x,&y);
edge[x][y]=edge[y][x]=1;
}
//如果存在奇数顶点,则从奇数顶点出发,否则从顶点0出发
int num=0,start=1;
for(int i=1;i<=n;i++){ //判断是否存在欧拉回路
int degree=0;
for(int j=1;j<=n;j++){
degree+=edge[i][j];
}
if(degree&1){
start=i,num++;
}
}
if(num==0||num==2){
Fleury(start);
}else
printf("No Euler Path\n");
return 0;
}