• 欧拉通路、回路


    欧拉通路: 通过图中每条边且只通过一次,并且经过每一顶点的通路

    欧拉回路: 通过图中每条边且只通过一次,并且经过每一顶点的回路

    有向图的基图:忽略有向图所有边的方向,得到的无向图称为该有向图的基图。 

    无向图

      设G是连通无向图,则称经过G的每条边一次并且仅一次的路径为欧拉通路;

     如果欧拉通路是回路(起点和终点是同一个顶点),则称此回路是欧拉回路

      具有欧拉回路的无向图G成为欧拉图

    有向图

    (1)设D是有向图,D的基图连通,则称经过D的每条边一次并且仅有一次的有向路径为 有向欧拉通路

    (2)如果有向欧拉通路是有向回路,则称此有向回路为  有向欧拉回路

    (3)具有有向欧拉回路的图D称为有向欧拉图

    定理

     无向图G存在欧拉通路的充要条件是:G为连通图,并且G仅有两个奇度结点(度数为奇数的顶点)或者无奇度结点。

    推论

    (1) 当G是仅有两个奇度结点的连通图时,G的欧拉通路必以此两个结点为端点;

    (2)当G是无奇度结点的连通图时,G必有欧拉回路

    (3)G为欧拉图(存在欧拉回路)的充分必要条件是  G为无奇度结点的连通图

     

    (有向图) 定理

    有向图D存在欧拉通路的充要条件是:D为有向图,D的基图连通,并且所有顶点的出度与入度相等;或者  除两个顶点外,其余顶点的出度与入度都相等,而这两个顶点中一个顶点的出度与入度之差为1,另一个顶点的出度与入度之差为-1.

    推论

    (1)当D除出、入度之差为1,-1的两个顶点之外,其余顶点的出度与入度相等时,D的有向欧拉通路必以出、入度之差为1的顶点作为始点,以出、入度之差为-1的顶点作为终点。

    (2)当D的所有顶点的出、入度都相等时,D中存在有向欧拉回路。

    (3)有向图D为有向欧拉图的充要条件是  D的基图为连通图,并且所有顶点的出、入度都相等。

     欧拉回路的求解

    两种方法:(1)DFS搜索  (Fleury)佛罗莱算法

    (1)DFS搜索 思想求解欧拉回路的思路为:利用欧拉定理判断出一个图存在欧拉通路或欧拉回路后,选择一个正确的起始顶点,用DFS算法遍历所有的边(每条边只遍历一次),遇到走不通就回退。在搜索前进方向上将遍历过的边按顺序记录下来。这组边的排列就组成了一条欧拉通路或回路。

    (2) (Fleury)佛罗莱算法

    设G为一个无向欧拉图,求G中一条欧拉回路的算法如下:

    (1) 任取G中一顶点v0,令P0=v0;

    (2)假设沿Pi=v0e1v1e2v2......eivi走到顶点vi,按下面方法从E(G)-{e1,e2,...,ei}中选ei+1。

            ei+1与vi相关联

            除非无别的边可供选择,否则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的一个割边集。若一条边构成一个割边集,则称该边为割边,或桥

    Dfs的方法

     #include<iostream>

    using namespace std;

    void dfs(int);

    int map[100][100];

    int du[100],path[100];

    int n,m,step;

    int main()

    {

          cin>>n>>m;

          for(int i=1;i<=m;i++)

          {

               int x,y;

               cin>>x>>y;

               map[x][y]=map[y][x]=1;

               du[x]++;

               du[y]++;

          }

          int start=1;

          for(int i=1;i<=n;i++)

            if(du[i]%2==1)

               start=i;

          step=0;

          dfs(start);

          for(int i=1;i<=step;i++)

            cout<<path[i]<<" ";

        return 0;

    }

    void dfs(int start)

    {

          int i;

          for( i=1;i<=n;i++)

           if(map[start][i]==1)

             {

                map[start][i]=map[i][start]=0;

                  dfs(i);

             }

          path[++step]=start;

    }

     

    佛罗莱算法

    //欧拉路径的输出(此图为无向图)

    #include<iostream>

    using namespace std;

    #define M 200

    struct stack

    {    int top,node[M];

    }s;             //顶点的栈结构

    int Edge[M][M]; //邻接矩阵

    int n;          //顶点个数

    void dfs(int x)   //这里的深度优先跟标准版有所区别,即不需要回溯

    {   s.top++;

        s.node[s.top]=x;   //将即将要扩展的结点压入栈中

        for(int i=0;i<n;i++)

        {

            if(Edge[i][x]) //如果该节点还存在边

            {

                Edge[i][x]=0; 

                Edge[x][i]=0;  //删除该边,然后搜索另一结点

                dfs(i);

                break;

            }

        }

    }

    void Fleury(int x)    //对头节点使用Fleury算法 查找欧拉路径

    {   s.top=0;

        s.node[s.top]=x;

        while(s.top>=0)

        {   int flag=0;  //记录当前结点是否有边可以扩展

            for(int i=0;i<n;i++)

            {

                if(Edge[i][s.top])

                {   flag=1;

                    break;

                }

            }

            if(!flag)

            {

                cout<<s.node[s.top]+1<<" "; //记录时是从0--n-1,所以应该加1

                s.top--;                    //结点输出了,此结点出栈

            }

            else

            {

                s.top--;              //因为dfs处理时,需要先进栈,所以这里要先出栈,然后再进栈

                dfs(s.node[s.top+1]); //处理那个结点

            }

        }

        cout<<endl;

    }

     

    int main()

    {

        int m,s,t;            //边数,读入的边的起点和终点

        int degree,num,start; //每个顶点的度、基度顶点个数、欧拉回路的起点

        cin>>n>>m;            //n---顶点数  m---边数

        memset(Edge,0,sizeof(Edge));

        for(int i=0;i<n;i++)

        {

            cin>>s>>t;

            Edge[s-1][t-1]=1;

            Edge[t-1][s-1]=1;

        }

        num=0;

        start=0;   //如果存在奇度顶点,则从奇度顶点出发,否则从顶点0出发

        for(int i=0;i<n;i++)

        {

            degree=0;

            for(int j=0;j<n;j++)

                degree+=Edge[i][j];

            if(degree%2)

            {

                num++;

                start=i;

            }

        }

        if(num==0||num==2) Fleury(start);

        else cout<<"No Euler path"<<endl;

        return 0;

    }

    模板(无向)

    dfs

    #include<iostream>
    #include<queue>
    using namespace std;
    int map[110][110],du[500][500],m,n,ans[110],sum,start;
    void dfs(int k)
    {
        
        for(int i=1;i<=du[k][0];i++)
        {
            if(map[k][du[k][i]]==1)
            {
                map[k][du[k][i]]=map[du[k][i]][k]=0;
                dfs(du[k][i]);
            }
        }ans[++sum]=k;
        cout<<k<<' ';
    }
    int main()
    {
        cin>>n>>m;
        int x,y;
        for(int i=1;i<=m;i++)
        {
            cin>>x>>y;
            map[x][y]=map[y][x]=1;
            du[x][++du[x][0]]=y;
            du[y][++du[y][0]]=x;
        }
        int cnt=0;
        start=1;
        for(int i=1;i<=n;i++)
        {
            if(du[i][0]%2==1)cnt++,start=i;
            if(du[i][0]==0){cout<<"no";return 0;}
        }
        if(cnt==0||cnt==2)dfs(start);
        else 
        {
            cout<<"no";
            return 0;
        }
    }
  • 相关阅读:
    关于我的介绍
    关于这周的作业
    关于这周的学习
    每周学习
    关于这周程序设计
    关于这周的总结
    关于这周的学习
    随机抽签程序报告
    Mysql的主从复制原理及部署
    项目架构脚本
  • 原文地址:https://www.cnblogs.com/thmyl/p/6286588.html
Copyright © 2020-2023  润新知