[笔记乱写]关于欧拉路
发现这个小东西虽然很简单但是考一次挂一次
A.定义
欧拉路:图中任意一个点开始到图中任意一个点结束,且通过的每条边只被通过一次的路径。
欧拉回路:同上,不过起点与终点相同。
B.判定
这里只以欧拉路为例。
无向图:对于一张无向图,当且仅当图联通且奇点数为0或2时,存在一条能遍历整张图的欧拉路。如果奇点数为2,那么这两个点应当作为欧拉路的起点和终点,否则任意一点都可作为欧拉路的起点和终点。
有向图:对于一张有向图,当且仅当图联通且有0个或2个点的入度不等于出度时,存在一条能遍历整张图的欧拉路。如果有2个点,那么这两个点当中一个必须入度=出度-1作为起点,另一个必须出度=入度-1作为终点,否则任意一点都可作为欧拉路的起点和终点。
C.算法
一般使用Hierholzer算法解决欧拉路问题,时间复杂度为$O(n+m)$。
首先来看优化前的$O(nm)$版本:
void dfs(int x) { for(int i=head[x];i;i=nxt[i]) { if(vis[i])continue; int y=to[i]; vis[i]=vis[i^1]=1;//The original edge_num should be 1. dfs(y); } st[++top]=x; }
很弱智是吧?
可能第一次看会觉得它不能保证形成包括所有边的方案,然而最后把点入栈的过程其实就是“拼凑”多条子欧拉路的过程。
所以只要这个图合法,最后一定可以得到一个经过所有边的方案。把栈内元素倒序输出即可。
不理解可以画个图手玩一下。
这种暴力算法的问题在于,虽然我们已经标记了走过的边,但还是到每个点时会从第一条边开始遍历,即使已经有一堆边不能走了。
怎么办呢?还记得dinic的当前弧优化吗?
没错,加上它就好了。
void dfs(int x) { for(int i=head[x];i;i=nxt[i]) { if(vis[i])continue; int y=to[i]; vis[i]=vis[i^1]=1;//The original edge_num should be 1. head[x]=i; dfs(y); i=head[x]; } st[++top]=x; }
那么我们就可以在$O(n+m)$的时间复杂度内求出一条欧拉路辣!
还有一件事……
这个算法的递归层数是$O(m)$级别的,就算没爆栈也会使递归过程奇慢无比。
所以大概还要手写系统栈用循环模拟一下:
int syst[N*10],systop; void euler() { systop=0; syst[++systop]=0; while(systop>0) { int x=syst[systop],i=head[x]; while(i&&v[i])i=nxt[i]; if(i) { syst[++systop]=to[i]; v[i]=v[i^1]=1; head[x]=nxt[i]; } else systop--,st[++top]=x; } }
完结撒花!
兴许青竹早凋,碧梧已僵,人事本难防。