[筆記亂寫]關於歐拉路

發現這個小東西雖然很簡單可是考一次掛一次算法

 

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

 

完結撒花!

相關文章
相關標籤/搜索