欧拉回路(转载)

欧拉回路

作为广大OIer的朋(gong)友(di)的欧拉,在图论中也贡(zuo)献(e)良(duo)多(duan),尤其是萌新经常会遇到以下两个恶心玩意。
欧拉路径:在一个图中,由i点出发,将每个边遍历一次最终到达j点的一条路径。
欧拉回路:i=j时的欧拉路径。
于是,如何确定一个图是否存在欧拉路径/回路,并找到这条路经,成为了出题人虐待萌新的法宝。

无向图

首先,在无向图中,要确定是否存在欧拉回路很容易:只要每个点的度数均为偶数即可。(这里就不扯什么连不连通的鬼东西了)。
因为每个点的度数为偶数,所以可以将整个图看做由数个环嵌套而成,因为环一定能找到一条欧拉回路,所以整个图也能找到欧拉回路。
这里写图片描述
欧拉路径:如果有且仅有两个点的度数为奇数,就会存在一条从这两个中的一个到达另一个的欧拉路径。
假如在这两个点间连一条边,就能够从任意一个点出发找到一条欧拉回路,当出发点为这两个点中的一个时,切断这条边,就成为一条欧拉路径了。
这里写图片描述

有向图

欧拉回路:所有点的入度等于出度,就存在一条欧拉回路。
这里可以换一种角度来理解,对于每一个点,每次进入这个节点,就一定有一条路可以出去,因此必定存在一条欧拉回路。
欧拉路径:最多有一点入度等于出度+1,最多有一点入度等于出度-1,就会有一条从出度大于入度(没有则等于)的点出发,到达出度小于入度(没有则等于)的点的一条欧拉路径。证明方法与无向图的欧拉路径类似。

至此,我们已经可以判断一个图是否存在欧拉回路/路径了。
接下来就是找出这条路经。首先,出发点我们在证明中已经确定,只需要保留路径时由后往前保存,再利用深搜回溯的过程,我们可以保证不会走死胡同(其实是走了死胡同,但保存路径时会把这段路留到最后,就相当于没有走死)。
因此,栈成为我最喜爱的保存路径的数据结构(先进后出)。

void dfs(int x){
    for(int i=0;i<a[x].size();i++)
        if(vis[x][i]==0){
            vis[x][i]=1;
            //delete(a[x][i],x);无向图要加这句
            dfs(a[x][i]);
            path.push(id[x][i]);//存储路径上的边
            cnt++;
        }
    ans.push(x);//存储路径上的点
}1234567891011

建议仔细分析一下:存储点和存储边的代码在位置上是否必须固定?如果不是,那么还能够怎么写?如果是,改成其他样子有什么结果?

注:有时候,你可能需要判断是否存在路径,一种很懒的做法是直接找路径,如果路径的长度等于给出的边数,就算有解,否则无解。

但其实这是错误的。
如果你真的理解了我刚才对算法的介绍,就会发现我的介绍是基于一定存在路径的基础上的。如果不存在路径,这个算法仍然会得出一个错误的解,这是由于搜索时,因为相信一定有解,所以会将一些不可行的边视为可行,自然会出错。

原帖地址

另外这两个也写的很好

[模板][持续更新]欧拉回路与欧拉路径浅析

图论的遍历 之 欧拉回路

猜你喜欢

转载自blog.csdn.net/qq_41428565/article/details/80440599