[筆記亂寫]關於歐拉路


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

 

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

 

完結撒花!

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM