欧拉路,欧拉回路

欧拉路,欧拉回路

1

经过图中所有边恰好一次的通路称为欧拉通路或欧拉路(通路一个点可以经过多次,如果是一个点只能通过一次为路径)
经过图中所有边恰好一次的回路称为欧拉回路,(回路是特殊的通路,起点和终点同一个点)

2 无向图欧拉路判断

欧拉回路的判别法:对于无向图G,G中存在欧拉回路当且仅当G中所有度非0的点是连通的且没有奇数度数的点

欧拉路的判断:对于无向图G,G中存在欧拉路当且仅当G中所有度非0的点是连通的,且奇数的点恰好有0个或者2个(0个即为欧拉回路)

3有向图欧拉路判断

欧拉回路的判别法:对于有向图G,G中存在欧拉回路当且仅当G中所有度非0的点是强连通的且每个点的入度和出度相同

欧拉路的判断:

{1将G中的有向边改成无向边后,G中所有非0的点是连通的,2最多只有一个出度减去入度为1,3最多只有一个点入度减出度为1 4其他所有点的入度等于出度}

4求欧拉路的流程 时间复杂度O(n+m)

先判断图中是否存在欧拉路(检查度非0的点的连通性以及度数)
      采用dfs来构造求解欧拉路,以有向图为例子:
        另P为最终的路径序列,记路径起点为x
      dfs(node u):{
     遍历u连出去的边u->v,且u->v之前是没有访问过的:
     dfs(v)
     将边u->v添加到路径序列P中
}
dfs(x)结束后,将P中记录的边倒序输出,求得欧拉路

5Code(有向图):

vector<int> edge[N+5];
int n,m,l,f[N+5],ind[N+5],outd[N+5],c[M+5];//f数组表示点x连出去的点已经遍历过几条了
inline void dfs(int x){
    int len=edge[x].size();
    for(;f[x]<len;){
        int y=edge[x][f[x]];
        f[x]++;
        dfs(y);
        c[++l]=y;
    }
}
inline void Euler(){
    int x=0,y=0,z=0;//x用来存起点的位置,y存入度比出度小一点的个数,z存入度和出度不同的点
    for(int i=1;i<=n;i++){
        if(ind[i]+1==outd[i])
            x=i,++y;
        if(ind[i]!=outd[i])
            ++z;
    }
    if(!(y==1&&z==2)||z){
        cout<<"NO\n";
        return;
    }
    //当不是所有点的入度和出度都相等时,只能存在(2最多只有一个出度减去入度为1,3最多只有一个点入度减出度为1)
    for(int i=1;i<=n;i++)
        if(ind[i])
            x=i;//随便取一个入度不为0的点设置为起点
    memset(f,0,sizeof(f));
    l=0;
    dfs(x);
    c[++l]=x;
    if(l==m+1)// 经过m条边,且每条边只经过一次,所有经过的点就有m+1个
    {
        cout<<"YES"<<'\n';
    for(int i=l;i;--i)
        cout<<c[i]<<' ';//逆序输出
    }
    else  cout<<"NO\n";
}

6Code(无向图):

struct Node{
    int y,idx;//y表示边走到哪,idx表示第几条边, 相同的边 边数相邻,可以直接通过异或1来获取 2^1=3,4^1=5等等
    Node(int _y,int _idx){y=_y;idx=_idx};
};
vector<Node> edge[N+5];
int n,m,l,cnt=1,f[N+5],v[N+5],d[N+5],c[M+5];
bool b[2*M+2];
inline void dfs(int x){
    for(;f[x]<v[x];){
        int y=edge[x][f[x]].y,idx=edge[x][f[x]].idx;
        if(!b[idx]){
            f[x]++;
            b[idx]=b[idx^1]=true;
            dfs(y);
            c[++l]=y;
        }else
            f[x]++;
    }
}
inline void Euler(){
    int x=0,y=0;//x表示起点,y表示度为奇数的点个数
    for(int i=1;i<=n;i++)
        if(d[i]&1)
            x=i,++y;
    if(y&&y!=2){
        cout<<"NO\n";
        return;
    }
    if(!x)
        for(int i=1;i<=n;i++)
            if(d[i])
                x=i;
    memset(f,0,sizeof(f));
    memset(b,false,sizeof(b));
    dfs(x);
    c[++l]=x;
    if(l!=m+1){
        cout<<"NO\n";
        return;
    }
    // 经过m条边,且每条边只经过一次,所有经过的点就有m+1个
    cout<<"YES\n";
    for(int i=l;i;--i)
        cout<<c[i]<<' ';
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值