彻底弄懂欧拉路问题

彻底弄懂欧拉路问题

石头于2014.11.23整理

起源历史

图论起源

图论起源于18世纪,1736年瑞士数学家欧拉(Euler)发表了图论的第一篇论文“哥尼斯堡七桥问题”。在当时的哥尼斯堡城有一条横贯全市的普雷格尔河,河中的两个岛与两岸用七座桥连结起来。当时那里的居民热衷于一个难题:有游人怎样不重复地走遍七桥,最后回到出发点。 为了解决这个问题,欧拉用A,B,C,D4个字母代替陆地,作为4个顶点,将联结两块陆地的桥用相应的线段表示,于是哥尼斯堡七桥问题就变成了图中,是否存在经过每条边一次且仅一次,经过所有的顶点的回路问题了。欧拉在论文中指出,这样的回路是不存在的。

一笔划:

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

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

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

基本概念:

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

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

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

通路和回路-称vie1e2envj为一条从 vi到 vj且长度为n的通路,其中长度是指通路中边的条数.称起点和终点相同的通路为一条回路。

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

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

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

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

 

欧拉生平

口欧拉(Euler)瑞士数学家,贡献遍及数学各领域,是数学史上最伟大的 数学家之一。生于公元1707415日。他的父亲保罗•欧拉(Paul Euler)是一名加尔文教派的教师,但欧拉在大学求学期间在雅各.伯 努利(Jacob Bernoulli)家住过并从雅各身上学了不少数学。

口保罗希望欧拉读神学,却犯了最大的错误,在欧拉很小的时候便教他 数学,挑动了他内心中的数学灵魂。而欧拉他最好的朋友就是大数学 家约翰.伯努利(John Bernoulli,雅各的弟弟)。约翰说:「欧拉注定

要成为大数学家,而非牧师。」最后保罗终于在约翰之劝说下同意欧 拉攻读数学。从此展开他灿烂的学术生涯,并成为数学史上最伟大的 数学家之一。

口欧拉对于数学的贡献是全面性的,基本上我们可以称他是一个百科全 书型的数学家。「他是有史以来瑞士最多产的科学家,也是一个不可 思议的数学幻想家,他在任何领域都能发现数学,在任何情况都能进 行研究。...

口欧拉一生都是在科学院度过。首先是在俄国的圣彼得堡科学院,1740 年后则在柏林科学院待到59岁。由于与腓特列大帝相处的问题,离开 柏林,接受凯萨琳女皇二世邀请再次前往圣彼得堡,一直到他过世( 1783年)。科学院的工作让他可以专心研究数学,全心全意地将整个 生命投入,就好像牧师将生命奉献给上帝一般。

口相对于牛顿的内向、退缩、神经质,欧拉则是乐观且仁慈宽厚,甚至 在1771年眼睛完全瞎掉,仍保有乐观的性格,在几乎完全失明之下, 仍藉由口述给他的助理(实际上就是他的儿子),来继续数学创作。

(其中包括需要烦琐计算之航海天文学的贡献)在后续的17年间欧拉 继续发展着数学,如果说有什么不同,那就是他比以前做得更多。他 的智慧使他巧妙地把握各种概念和想法而无需将它们书写在纸上,他 非凡的记忆力,使他的头脑有如一个堆满知识的图书馆。

口欧拉、牛顿与莱布尼兹都是属于新数学理论的开拓者,有 人将欧拉、高斯、黎曼在数学的地位比喻为乐坛上的三B :巴哈、贝多芬、布拉姆斯,也有人将欧拉比拟为数学界 的莎士比亚:

普世性、巨细靡遗、取之不尽、用之不竭。

口 Read Euler, read Euler, he is the master of us all.

P.-S.de Laplace

欧拉图的特征

 无向图

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

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

 有向图

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

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

现代扩展

对欧拉图的一个现代扩展是蜘蛛图,它向欧拉图增加了可以连接的存在点。这给予欧拉图析取特征。欧拉图已经有了合取特征(就是说区定义了有着与起来的那些性质的对象在区中的存在)。所以蜘蛛图允许使用欧拉图建模逻辑或的条件。

相关定理

1.无向连通图G是欧拉图,当且仅当G不含奇数度结点(G的所有结点度数为偶数)

2.无向连通图G含有欧拉通路,当且仅当G有零个或两个奇数度的结点;

3.有向连通图D是欧拉图,当且仅当该图为连通图且D中每个结点的入度=出度

4.有向连通图D含有欧拉通路,当且仅当该图为连通图且D中除两个结点外,其余每个结点的入度=出度,且此两点满足(起始点s的入度=出度-1,结束点t的出度=入度-1 或两个点的入度=出度)

5.一个非平凡连通图是欧拉图当且仅当它的每条边属于奇数个环。 

6.如果图G是欧拉图且 H = G - uv,则H有奇数个u,v-迹仅在最后访问v;同时,在这一序列的u,v-迹中,不是路径的迹的条数是偶数。(Todia[1973])//??????????

弗罗莱(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)

欧拉算法的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);									//见附录 linkqueue
       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;
}

实现二

//无向图欧拉通路(num==2)、欧拉回路(num==0)Fleury模板:

#include <iostream>
#include <stdio.h>
#include <string.h>
#define MAXN 200
using namespace std;
struct stack{
    int top,node[MAXN];
}s;
int Edge[MAXN][MAXN];
int n;
void dfs(int x){
    int i;
    s.top++;
    s.node[s.top]=x;
    for(i=0;i<n;i++){
        if(Edge[i][x]>0){
            Edge[i][x]=0;
            Edge[x][i]=0;
            dfs(i);
            break;
        }
    }
}
void Fleury(int x){
    int i,b;
    s.top=0;s.node[s.top]=x;
    while(s.top>=0){
        b=0;
        for(i=0;i<n;i++){
            if(Edge[s.node[s.top]][i]>0){
                b=1;break;
            }
        }
        if(b==0){
            printf("%d ",s.node[s.top]+1);
            s.top--;
        }
        else{
            s.top--;
            dfs(s.node[s.top+1]);
        }
    }
    printf("\n");
}
int main()
{
    freopen("in.txt","r",stdin);
    int i,j;
    int m,s,t;
    int degree,num,start;
    while(scanf("%d%d",&n,&m)!=EOF){
        memset(Edge,0,sizeof(Edge));
        for(i=0;i<m;i++){
            scanf("%d%d",&s,&t);
            Edge[s-1][t-1]=1;
            Edge[t-1][s-1]=1;
        }
        num=0;start=0;
        for(i=0;i<n;i++){
            degree=0;
            for(j=0;j<n;j++)
                degree+=Edge[i][j];
            if(degree%2==1){
                start=i;
                num++;
            }
        }
        if(num==0 || num==2) Fleury(start);
        else printf("No Euler path\n");
    }
    return 0;
}

/*          1**********2********3    

Input: *    *  *        *               

9 14        *     *    *        *       

1 2         *   *      *        *       

1 8  8**********9********4

2 3         *          *      * *

2 8         *          *   *    *

2 9         *          * *      *

3 4         7**********6********5

4 5E[0][1]==0 E[0][7]==0

4 6E[1][0]==0 E[1][2]==0 E[1][7]==0 E[1][8]==0

4 9

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值