[笔记乱写]关于欧拉路

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

 

A.定义

欧拉路:图中任意一个点开始到图中任意一个点结束,且经过的每条边只被经过一次的路径。优化

欧拉回路:同上,不过起点与终点相同。spa

B.断定

这里只以欧拉路为例。blog

无向图:对于一张无向图,当且仅当图联通且奇点数为0或2时,存在一条能遍历整张图的欧拉路。若是奇点数为2,那么这两个点应看成为欧拉路的起点和终点,不然任意一点均可做为欧拉路的起点和终点。递归

有向图:对于一张有向图,当且仅当图联通且有0个或2个点的入度不等于出度时,存在一条能遍历整张图的欧拉路。若是有2个点,那么这两个点当中一个必须入度=出度-1做为起点,另外一个必须出度=入度-1做为终点,不然任意一点均可做为欧拉路的起点和终点。class

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

 

很弱智是吧?top

可能第一次看会以为它不能保证造成包括全部边的方案,然而最后把点入栈的过程其实就是“拼凑”多条子欧拉路的过程。di

因此只要这个图合法,最后必定能够获得一个通过全部边的方案。把栈内元素倒序输出便可。

不理解能够画个图手玩一下。

 

这种暴力算法的问题在于,虽然咱们已经标记了走过的边,但仍是到每一个点时会从第一条边开始遍历,即便已经有一堆边不能走了。

怎么办呢?还记得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;
    }
}

 

完结撒花!

相关文章
相关标签/搜索