弗罗莱(Fleury)算法 欧拉(Euler)通路/回路

1、基本概念:

1)欧拉图的基本概念:

欧拉通路 (欧拉迹):通过图中每条边一次且仅一次,并且过每一顶点的通路。

欧拉回路 (欧拉闭迹):通过图中每条边一次且仅一次,并且过每一顶点的回路。

欧拉图:存在欧拉回路的图。欧拉图就是从一顶点出发每条边恰通过一次又能回到出发顶点的那种图,即不重复的行遍所有的边再回到出发点。

通路和回路:vie1e2…envj为一条从 vi vj且长度为n通路,其中长度是指通路中边的条数.称起点和终点相同的通路为一条回路

简单图:不含平行边和自回路的图。

混合图:既有有向边,也有无向边的图

平凡图:仅有一个结点的图

完全图:n个结点的且每对结点都有边相连的无向简单图,称为无向完全图;有n个结点的且每对结点之间都有两条方向相反的边相连的有向简单图为有向完全图。

2)欧拉图的特征:
 
无向图

aG有欧拉通路的充分必要条件为:连通,G中只有两个奇度顶点(它们分别是欧拉通路的两个端点)

bG有欧拉回路(G为欧拉图)G连通,G中均为偶度顶点。 
 
有向图

aD有欧拉通路:D连通,除两个顶点外,其余顶点的入度均等于出度,这两个特殊的顶点中,一个顶点的入度比出度大1,另一个顶点的入度比出度小1

bD有欧拉回路(D为欧拉图)D连通,D中所有顶点的入度等于出度。一个有向图是欧拉图,当且仅当该图所有顶点度数都是0

2 、弗罗莱(Fleury )算法思想-解决欧拉回路

    Fleury算法:
   
任取v0V(G),令P0=v0

Pi=v0e1v1e2ei vi已经行遍,按下面方法从中选取ei+1

aei+1vi相关联;

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++) //v是顶点数,e是边数
        if(G[i][x]>0)  
         {
          k=1;
          G[i][x]=0; G[x][i]=0; //此边已访问,删除此边
          DFS(G,S,i,0);//寻找下一条关联的边,本次找到的是与x关联的i,在
                        //下一层中将寻找与i关联的边
          break;
         }//if,for
       if(k==0)       //如果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);//
              }//if
              else   //搜寻完毕,将最后节点也入栈
                     Push(S,x);
       }//if
}//DFS
 
void Euler(Graph &G,int x)
{
//G是存储图的邻接矩阵,都处理成无向图形式,值为1代表有边,0代表无边,不包括自回路,x是出发点
InitStack(S);//用来存放遍历边时依次走过的顶点
DFS(G,S,x,0);//深度优先遍历查找,0是指查询的起点
//输出
 while(!StackEmpty(S))
 {
  GetTop(S,m);
  printf("->v%d",m);
  Pop(S);
 }//while
}//Euler</span>

如下为算法的图示动态过程:

13、弗罗莱(Fleury)算法,求欧拉(Euler)通路/回路 - 墨涵 - 墨涵天地

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,for
       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);
              }//if
              else
                     Push(S,x);
       }//if
}//DFS
 
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);
                            }//if
       }//while
       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);
       }//while
}
 
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;
  }//for
}//InputM1
 
int main()
{
       int i,j,sum,k=0;
       Graph G;
       InputM1(G);
       if(BFSTest(G)==0)
       {
              printf("该图不是连通图!\n");
              exit(0);
       }//if
       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
       }//for
       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年研究并解决了此问题,他把问题归结为如下右图的一笔画问题,证明上述走法是不可能的。

13、弗罗莱(Fleury)算法,求欧拉(Euler)通路/回路 - 墨涵 - 墨涵天地

一笔划

⒈凡是由偶点组成的连通图,一定可以一笔画成。画时可以把任一偶点为起点,最后一定能以这个点为终点画完此图。

⒉凡是只有两个奇点的连通图(其余都为偶点),一定可以一笔画成。画时必须把一个奇点为起点,另一个奇点终点。

⒊其他情况的图都不能一笔画出。(奇点数除以二便可算出此图需几笔画成。)



  • 4
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值