UOJ 117 欧拉回路
Posted mrclr
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了UOJ 117 欧拉回路相关的知识,希望对你有一定的参考价值。
正如题目所述,这就是一道板子题。
不过身为一道板子题,数据还是非常负(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 }
以上是关于UOJ 117 欧拉回路的主要内容,如果未能解决你的问题,请参考以下文章