歐拉回路學習筆記
阿新 • • 發佈:2021-10-19
歐拉回路是從圖上某一點出發,經過一系列不重複的邊,然後再回到開始節點的路徑。
1.定義
通俗的講,歐拉回路是從圖上某一點出發,經過一系列不重複的邊,然後再回到開始節點的路徑。
注意,這個過程可以經過重複的節點 比如圖中僅有一個點,有 \(998244353\) 個自環,但這些自環仍然可以構成歐拉回路。
2.存在條件
- 有向圖
每個節點入度等於出度 - 無向圖
每個節點度均為偶數
3.求解方法
比較簡單,從一個點出發進行dfs,在回溯的時候把當前邊加入答案佇列。
但有以下情況需要考慮
- 圖不連通
無解。前提是至少兩個連通塊內有邊 - 單獨一個點
可以忽略,不對答案產生影響。因為歐拉回路關心的是經過所有邊 單獨一個點不會影響答案 - 優化
如果不加當前弧優化,複雜度是 \(O(nm)\)
加上後能優化到 \(O(n+m)\)
4.例題&程式碼
模板-UOJ117
分別對有向圖和無向圖找出歐拉回路,輸出路徑。
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<map> #include<cstring> #include<stack> #include<queue> #include<vector> #include<bitset> #define ll long long using namespace std; const int inf = 0x7fffffff; int T,n,m; #define maxn 400009 int in[maxn],ans[maxn],out[maxn]; int nxt[maxn],head[maxn],to[maxn]; bool ban[maxn],vis[maxn]; namespace fuckccf//無向邊 { int num=0,cnt=1;//!!!從1開始記錄 void Add(int x,int y){cnt++;nxt[cnt]=head[x];to[cnt]=y;head[x]=cnt;}//鄰接表 void dfs(int x) { ban[x]=1; for(int &i=head[x];i;i=nxt[i])//當前弧 { int t=to[i],j=i>>1,val=i;//!!!進行完dfs之後i的值會改變 要提前存下來 if(vis[j])continue; vis[j]=1; dfs(t); num++; if(val&1)ans[num]=-j;//如果是正向的 i末尾是0 否則是1 else ans[num]=j; } } void main() { scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) { int x,y; scanf("%d%d",&x,&y); Add(x,y); Add(y,x); in[x]++; in[y]++; } for(int i=1;i<=n;i++)if(in[i]&1){printf("NO\n");return;}//判斷無解 for(int i=1;i<=n;i++) { if(!ban[i])dfs(i); if(num&&num<m)//走了一些邊,但沒走完,說明圖不連通或者無解 { printf("NO\n"); return; } } printf("YES\n"); for(int i=m;i>=1;i--) { printf("%d ",ans[i]); } } } namespace tymXINzhy//有向邊 { int num=0,cnt=0; void Add(int x,int y){cnt++;nxt[cnt]=head[x];to[cnt]=y;head[x]=cnt;} void dfs(int x) { ban[x]=1; for(int &i=head[x];i;i=nxt[i]) { int t=to[i],val=i; if(vis[i])continue; vis[i]=1; dfs(t); num++; ans[num]=val;//直接記錄邊即可 } } void main() { scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) { int x,y; scanf("%d%d",&x,&y); Add(x,y); in[y]++; out[x]++; } for(int i=1;i<=n;i++)if(in[i]!=out[i]){printf("NO\n");return;} for(int i=1;i<=n;i++) { if(!ban[i])dfs(i); if(num&&num<m) { printf("NO\n"); return; } } printf("YES\n"); for(int i=m;i>=1;i--) { printf("%d ",ans[i]); } } } signed main() { // freopen("h.in","r",stdin); scanf("%d",&T); if(T==1)fuckccf::main(); else tymXINzhy::main(); return 0; } `