1. 程式人生 > >UOJ 117 歐拉回路

UOJ 117 歐拉回路

fin ems () 並查集 tar 數組 不能 ctype fine

嘟嘟嘟

正如題目所述,這就是一道板子題。

不過身為一道板子題,數據還是非常負(du)責(liu)的。

一點點講。

1.判斷歐拉圖

  判斷無向圖是歐拉圖就是所有點的度數都是偶數;判斷有向圖是歐拉圖就是所有點的入度等於出度。

  但是僅這樣是不行的,還有判斷圖是否連通。這個可以用並查集實現。或者是看dfs經過的所有邊是否等於m。

2.求歐拉回路

  對於一個點x,如果有一條邊(x->y)沒走過,就接著dfs(y),並把(x->y)加入記錄答案的棧中。最後倒序輸出。

  所以要有一個標記數組。

  對於無向圖,建圖的時候是把(x, y)拆成(x->y)和(y->x)兩條邊,因此標記的時候我們要一次把兩條邊都標記了。不過有一個更簡便的方法:兩條邊的編號一定是e和e + 1,雖然邊存了雙倍,但是標記的時候只用標記e >> 1,判斷的時候對於e和e +1,都判斷e >> 1是否走過即可。因此,ecnt要從2開始計數,所以初始化ecnt = 1。

  對於有向圖,如果只想寫一遍dfs,開一個標記數組的話,可以模仿無向圖的存邊方式,隔一個一存,這樣就和無向圖統一了。

  樸素的dfs會TLE,因此每一個點要加上弧優化。在保證正確性的前提下較簡潔的寫法請看下面的代碼。

  duliu的數據告訴我們1~n中有些點可能不存在,所以不能默認從1開始dfs。所以再開一個變量s,存圖中存在的任意一個點,然後從dfs(s)開始即可。可是數據過分的負責,有m = 0的點,所以s一定要賦初值0,這樣dfs(0)什麽也沒有就退出來了,防止因s沒賦初值而不知道從哪兒開始dfs然後RE。

3.輸出答案

  在代碼中ans存的是雙倍的邊的編號。如果ans[i]是奇數編號,那麽一定是人為添加的反向邊,輸出-(ans[i] >> 1),否則輸出正的。

4.祝Debug愉快。

技術分享圖片
 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cmath>
 4 #include<algorithm>
 5 #include<cstring>
 6 #include<cstdlib>
 7 #include<cctype>
 8 #include<vector>
 9 #include<stack>
10 #include<queue>
11 using namespace std;
12 #define enter puts("") 13 #define space putchar(‘ ‘) 14 #define Mem(a, x) memset(a, x, sizeof(a)) 15 #define rg register 16 typedef long long ll; 17 typedef double db; 18 const int INF = 0x3f3f3f3f; 19 const db eps = 1e-8; 20 const int maxn = 1e5 + 5; 21 const int maxm = 2e5 + 5; 22 inline ll read() 23 { 24 ll ans = 0; 25 char ch = getchar(), last = ; 26 while(!isdigit(ch)) {last = ch; ch = getchar();} 27 while(isdigit(ch)) {ans = ans * 10 + ch - 0; ch = getchar();} 28 if(last == -) ans = -ans; 29 return ans; 30 } 31 inline void write(ll x) 32 { 33 if(x < 0) x = -x, putchar(-); 34 if(x >= 10) write(x / 10); 35 putchar(x % 10 + 0); 36 } 37 38 int n, m; 39 struct Edge 40 { 41 int to, nxt; 42 }e[maxm << 1]; 43 int head[maxn], ecnt = 1; 44 void addEdge(int x, int y) 45 { 46 e[++ecnt] = (Edge){y, head[x]}; 47 head[x] = ecnt; 48 } 49 50 int ans[maxm << 1], cnt = 0; 51 bool vis[maxm]; 52 int in[maxn], out[maxn]; 53 void dfs(int now) 54 { 55 for(int &i = head[now]; i; i = e[i].nxt) 56 { 57 int tp = i; 58 if(!vis[tp >> 1]) 59 { 60 vis[tp >> 1] = 1; 61 dfs(e[tp].to); 62 ans[++cnt] = tp; 63 } 64 } 65 } 66 67 int main() 68 { 69 int s = 0, t = read(); 70 n = read(); m = read(); 71 for(int i = 1; i <= m; ++i) 72 { 73 int x = read(), y = read(); 74 s = x; 75 addEdge(x, y); 76 if(t == 1) addEdge(y, x), in[x]++, in[y]++; 77 else ecnt++, out[x]++, in[y]++; 78 } 79 if(t == 1) 80 { 81 for(int i = 1; i <= n; ++i) 82 if(in[i] & 1) {puts("NO"); return 0;} 83 } 84 else 85 { 86 for(int i = 1; i <= n; ++i) 87 if(in[i] != out[i]) {puts("NO"); return 0;} 88 } 89 dfs(s); 90 if(cnt != m) puts("NO"); 91 else 92 { 93 puts("YES"); 94 for(int i = cnt; i; --i) write((ans[i] & 1) ? -(ans[i] >> 1) : (ans[i] >> 1)), space; 95 enter; 96 } 97 return 0; 98 }
View Code

UOJ 117 歐拉回路