转载地址:http://blog.csdn.net/zyy617532750/article/details/50981888
1、基本概念:
(1)欧拉图的基本概念:
欧拉通路 (欧拉迹):通过图中每条边一次且仅一次,并且过每一顶点的通路。
欧拉回路 (欧拉闭迹):通过图中每条边一次且仅一次,并且过每一顶点的回路。
欧拉图:存在欧拉回路的图。欧拉图就是从一顶点出发每条边恰通过一次又能回到出发顶点的那种图,即不重复的行遍所有的边再回到出发点。
通路和回路:称vie1e2…envj为一条从 vi到 vj且长度为n的通路,其中长度是指通路中边的条数.称起点和终点相同的通路为一条回路。
简单图:不含平行边和自回路的图。
混合图:既有有向边,也有无向边的图
平凡图:仅有一个结点的图
完全图:有n个结点的且每对结点都有边相连的无向简单图,称为无向完全图;有n个结点的且每对结点之间都有两条方向相反的边相连的有向简单图为有向完全图。
(2)欧拉图的特征:
无向图
a)G有欧拉通路的充分必要条件为:G 连通,G中只有两个奇度顶点(它们分别是欧拉通路的两个端点)。
b)G有欧拉回路(G为欧拉图):G连通,G中均为偶度顶点。
有向图
a)D有欧拉通路:D连通,除两个顶点外,其余顶点的入度均等于出度,这两个特殊的顶点中,一个顶点的入度比出度大1,另一个顶点的入度比出度小1。
b)D有欧拉回路(D为欧拉图):D连通,D中所有顶点的入度等于出度。一个有向图是欧拉图,当且仅当该图所有顶点度数都是0。
2
、弗罗莱(Fleury
)算法思想-解决欧拉回路
Fleury算法:
任取v0∈V(G),令P0=v0;
设Pi=v0e1v1e2…ei vi已经行遍,按下面方法从中选取ei+1:
(a)ei+1与vi相关联;
(b)除非无别的边可供行遍,否则ei+1不应该为Gi=G-{e1,e2, …, ei}中的桥(所谓桥是一条删除后使连通图不再连通的边);
(c)当(b)不能再进行时,算法停止。
可以证明,当算法停止时所得的简单回路Wm=v0e1v1e2….emvm(vm=v0)为G中的一条欧拉回路,复杂度为O(e*e)。
3
、欧拉算法C
语言描述
- void DFS(Graph &G,SqStack &S,int x,int t)
- {
- k=0;
- Push(S,x);
- for(i=t;i<v;i++)
- if(G[i][x]>0)
- {
- k=1;
- G[i][x]=0; G[x][i]=0;
- DFS(G,S,i,0);
-
- break;
- }
- if(k==0)
- {
- Pop(S);
- GetTop(S,m);
- G[x][m]=1;G[m][x]=1;
- a=x+1;
- if(StackLength(S)!=e)
- {
- Pop(S);
- DFS(G,S,m,a);
- }
- else
- Push(S,x);
- }
- }
-
- void Euler(Graph &G,int x)
- {
-
- InitStack(S);
- DFS(G,S,x,0);
-
- while(!StackEmpty(S))
- {
- GetTop(S,m);
- printf("->v%d",m);
- Pop(S);
- }
- }
如下为算法的图示动态过程:
4、欧拉算法的C实现
- #include "SqStack.h" //堆栈的常见操作
- #include "Queue.h"//队列的常见操作
-
- typedef int Graph[200][200];
- int v,e;
-
- void DFS(Graph &G,SqStack &S,int x,int t)
- {
- int k=0,i,m,a;
- Push(S,x);
- for(i=t;i<v;i++)
- if(G[i][x]>0)
- {
- k=1;
- G[i][x]=0;
- G[x][i]=0;
- DFS(G,S,i,0);
- break;
- }
- if(k==0)
- {
- Pop(S);
- GetTop(S,m);
- G[x][m]=1;
- G[m][x]=1;
- a=x+1;
- if(StackLength(S)!=e)
- {
- Pop(S);
- DFS(G,S,m,a);
- }
- else
- Push(S,x);
- }
- }
-
- int BFSTest(Graph G)
- {
- int a[200],x,i,k=0;
- LinkQueue Q;
- InitQueue(Q);
- EnQueue(Q,0);
- for(i=0;i<v;i++)
- a[i]=0;
- a[0]=1;
- while(!QueueEmpty(Q))
- {
- DeQueue(Q,x);
- for(i=0;i<v;i++)
- if(G[x][i]>0)
- if(a[i]!=1)
- {
- a[i]=1;
- EnQueue(Q,i);
- }
- }
- for(i=0;i<v;i++)
- if(a[i]==0)
- {
- k=1;
- break;
- }
- if(k==1)
- return 0;
- else
- return 1;
- }
-
- void Euler(Graph &G,int x)
- {
- int m;
- SqStack S;
- InitStack(S);
- DFS(G,S,x,0);
- printf("该图的一个欧拉回路为:");
- while(!StackEmpty(S))
- {
- GetTop(S,m);
- printf("->v%d",m);
- Pop(S);
- }
- }
-
- void InputM1(Graph &G)
- {
-
- int h,z;
- printf("Please input 顶点数和边数\n");
- scanf("%d",&v);
- scanf("%d",&e);
- for(int i=0;i<v;i++)
- for(int j=0;j<v;j++)
- G[i][j]=0;
-
- printf("please int the 邻接矩阵的值(起点(数字) 终点(数字)):\n");
- for(int i=0;i<e;i++)
- {
- scanf("%d",&h);
- scanf("%d",&z);
- G[h-1][z-1]=1;
- G[z-1][h-1]=1;
- }
- }
-
- int main()
- {
- int i,j,sum,k=0;
- Graph G;
- InputM1(G);
- if(BFSTest(G)==0)
- {
- printf("该图不是连通图!\n");
- exit(0);
- }
- for(i=0;i<v;i++)
- {
- sum=0;
- for(j=0;j<v;j++)
- sum+=G[i][j];
- if(sum%2==1)
- { k=1;
- break;
- }
- }
- if(k==1) printf("该图不存在欧拉回路!\n");
- else
- Euler(G,0);
- return 1;
- }
- 顶点数5,边数为6
- 相关联的点1 2
- 1 3
- 2 5
- 4 2
- 3 2
- 4 5
5、小常识:欧拉算法的起由及一笔画问题
七桥问题:18世纪著名古典数学问题之一。在哥尼斯堡的一个公园里,有七座桥将普雷格尔河中两个岛及岛与河岸连接起来(如图)。问是否可能从这四块陆地中任一块出发,恰好通过每座桥一次,再回到起点?欧拉于1736年研究并解决了此问题,他把问题归结为如下右图的“一笔画”问题,证明上述走法是不可能的。
一笔划:
⒈凡是由偶点组成的连通图,一定可以一笔画成。画时可以把任一偶点为起点,最后一定能以这个点为终点画完此图。
⒉凡是只有两个奇点的连通图(其余都为偶点),一定可以一笔画成。画时必须把一个奇点为起点,另一个奇点终点。
⒊其他情况的图都不能一笔画出。(奇点数除以二便可算出此图需几笔画成。)