發現這個小東西雖然很簡單可是考一次掛一次算法
歐拉路:圖中任意一個點開始到圖中任意一個點結束,且經過的每條邊只被經過一次的路徑。優化
歐拉回路:同上,不過起點與終點相同。spa
這裏只以歐拉路爲例。blog
無向圖:對於一張無向圖,當且僅當圖聯通且奇點數爲0或2時,存在一條能遍歷整張圖的歐拉路。若是奇點數爲2,那麼這兩個點應看成爲歐拉路的起點和終點,不然任意一點均可做爲歐拉路的起點和終點。遞歸
有向圖:對於一張有向圖,當且僅當圖聯通且有0個或2個點的入度不等於出度時,存在一條能遍歷整張圖的歐拉路。若是有2個點,那麼這兩個點當中一個必須入度=出度-1做爲起點,另外一個必須出度=入度-1做爲終點,不然任意一點均可做爲歐拉路的起點和終點。class
通常使用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; } }
完結撒花!