[笔记乱写]关于欧拉路

发现这个小东西虽然很简单但是考一次挂一次

 

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;
    }
}

 

完结撒花!

 

posted @ 2019-11-04 21:43  Rorschach_XR  阅读(546)  评论(2编辑  收藏  举报
//雪花飘落效果