1、定义:
欧拉通路(回路):通过图(无向图或有向图)中所有边一次且仅一次行遍图中所有顶点的
通路(回路)称为欧拉通路(回路)。
欧拉图与半欧拉图:具有欧拉回路的图称为欧拉图,具有欧拉通路而无欧拉回路的
图称为半欧拉图。
桥:设无向图G=<V,E>,若存在边集E的一个非空子集E1,使得p(G-E1)>p(G),而对
于E1的任意真子集E2,均有p(G-E2)=p(G),则称E1是G的边割集,或简称割集;
若E1是单元集,即E1={e},则称e为割边或桥。[p(G)表示图G的连通分支数.]
2、定理:
<无向图>
定理1:无向图G是欧拉图当且仅当G是连通图,且G中没有奇度顶点。
定理2:无向图G是半欧拉图当且仅当G是连通图,且G中恰有两个奇度顶点。
<有向图>
定理1:有向图D是欧拉图当且仅当D是强连通的且每个顶点的入度都等于出度。
定理2:有向图D是半欧拉图当且仅当D是单向连通的,且D中恰有两个奇度顶点,其
中一个入度比出度大1,另一个的出度比入度大1,而其余顶点的入度都等于
出度。
3、求欧拉回路的Fleury算法:
设G为欧拉图,一般说来G中存在若干条欧拉回路,下面是求欧拉回路的Fleury算法:
Fleury算法:
(1)任取v0∈V(G),令P0=v0;
(2)设Pi=v0e1v1e2...eivi已经行遍,按下面方法来从E(G)-{e1,e2,...,ei}中选
取ei+1:
(a)ei+1与vi想关联;
(b)除非无别的边可供行遍,否则ei+1不应该为Gi=G-{e1,e2,...,ei}中的桥.
(3)当(2)不能再进行时,算法停止。
可以证明,当算法停止时所得简单回路Pm=v0e1v1e2...emvm(vm=v0)为G中的一条欧拉回路
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<stack>
using namespace std;
stack<int>que;
int a[1000][1000];
int n,m;
void dfs(int x)
{
int i;
que.push(x);
for(i=1;i<=n;i++)
{
if(a[x][i]>0)
{
a[x][i]=0;
a[i][x]=0;
dfs(i);
break;
}
}
}
void fleury(int x)
{
int i,j;
int b;
que.push(x);
while(!que.empty())
{
b=0;
for(i=1;i<=n;i++)
{
if(a[que.top()][i]>0)
{
b=1;
break;
}
}
if(b==0)
{
printf("%d ",que.top());
que.pop();
}
else
{
int y=que.top();
que.pop();
dfs(y);
}
}
printf("\n");
return ;
}
int main()
{
int i,j,p,q;
while(scanf("%d %d",&n,&m)!=EOF)
{
memset(a,0,sizeof(a));
for(j=1;j<=m;j++)
{
scanf("%d %d",&p,&q);
a[p][q]=a[q][p]=1;
}
int num=0;
int start=1;
int degree=0;
for(i=1;i<=n;i++)
{
degree=0;
for(j=1;j<=n;j++)
{
degree+=a[i][j];
}
if(degree%2==1)
{
start=i;
num++;
}
}
if(num==0||num==2)
{
fleury(start);
}
else
{
printf("NO Eular path\n");
}
while(!que.empty())
{
que.pop();
}
}
return 0;
}