1. Fleury(佛罗莱)算法
设G为一无向欧拉图,求G中一条欧拉回路的算法为:
1) 任取G中一顶点v0,令P0 = v0;
2) 假设沿Pi = v0e1v1e2v2 …eivi走到顶点vi,按下面方法从E(G)- { e1, e2, …, ei}中选ei+1:
a) ei+1与vi相关联;
b) 除非无别的边可供选择,否则ei+1不应该是Gi = G - { e1, e2, …, ei}中的桥。
3) 当2)不能再进行时算法停止。
可以证明的是,当算法停止时,所得到的简单回路Pm= v0e1v1e2v2 …emvm, (vm= v0)为G中一条欧拉回路。
桥
设无向图G(V, E)为连通图,若边集E1⊆E,在图G中删除E1中所有的边后得到的子图是不连通的,而删除了E1的任一真子集后得到的子图是连通图,则称E1是G的一个割边集。若一条边构成一个割边集,则称该边为割边,或桥 。
例如,如下图G所示的无向连通图,边(1, 5)、(4, 6)、(8, 10)和(8, 9)都是图G中的桥。
题目描述:用Fleury算法输出下图(a)中的欧拉回路。
输入描述:
假设数据输入时采用如下的格式进行输入:首先输入顶点个数n和边数m,然后输入每条边,每条边的数据占一行,格式为:u v,表示从顶点u到顶点v的一条有向边。
输出描述:
在下面的代码中,首先判断是否存在欧拉回路或通路,如果存在则选择一个正确的顶点按照Fleury算法输出欧拉回路或通路。
#include <iostream>
#include <cstring>
using namespace std;
const int MAXN = 200;
struct Stack
{
int top;
int node[MAXN];
}s;//顶点的栈结构
int Edge[MAXN][MAXN];//储存图的邻接矩阵
int n;//顶点个数
void DFS( int x )//从x开始搜索,直到无法进行下去时,搜索结束
{
s.top++;
s.node[ s.top ] = x;
int i;
for(i = 0; i < n; ++i)
{
if(Edge[x][i] > 0)//每走一步就要删除该边
{
Edge[x][i] = Edge[i][x] = 0;
DFS( i );
break;
}
}
return;
}
void Fleury( int start )
{
int i;
s.top = 0;
s.node[ s.top ] = start;
while( s.top >= 0 )
{
int b = 0;
for(i = 0; i < n; ++i)
{
if(Edge[ s.node[s.top] ][i] > 0)
{
b = 1;
break;
}
}
if(b == 0)//如果b = 0说明,Edge[s.node[ s.top-1 ] ][ s.node[ s.top ] ]是桥,
{ //而该栈顶元素一定会由次栈顶元素s.node[s.top-1]经过该桥到达,s.node[ s.top ]也无法继续拓展下去,可以直接输出
cout<<s.node[ s.top ] + 1<<" ";
s.top--;
}
else
{
s.top--;
DFS( s.node[s.top + 1] );//如果有,那就继续拓展下去
}
}
cout<<endl;
}
int main()
{
int i, j;
int m, s, t; //边数,读入的边的起点和终点
int degree, num, start;//每个顶点的度、奇度顶点个数、欧拉回路的起点
cin>>n>>m;//n顶点数、m边数
memset( Edge, 0, sizeof(Edge) );
for(i = 0; i < m; ++i)
{
cin>>s>>t;
Edge[ s-1 ][ t-1 ] = Edge[ t-1 ][ s-1 ] = 1;
}
//如果存在奇度顶点,则从奇度顶点出发,否则从顶点0出发
num = start = 0;
for(i = 0; i < n; ++i)//判断是否存在欧拉回路
{
degree = 0;
for(j = 0; j < n; ++j)
degree += Edge[i][j];
if(degree % 2 == 1)
{
num++;
start= i;
}
}
if(num == 0 || num == 2)
Fleury( start );
else
cout<<"No Euler path"<<endl;
return 0;
}
/**
9 14
1 2
1 8
2 3
2 8
2 9
3 4
4 5
4 6
4 9
5 6
6 7
6 9
7 8
8 9
*/