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 }
View Code

 

以上是关于UOJ 117 欧拉回路的主要内容,如果未能解决你的问题,请参考以下文章

算法复习——欧拉回路(uoj117)

uoj117:欧拉回路——题解

UOJ117. 欧拉回路

UOJ 117欧拉回路

UOJ 117 欧拉回路

UOJ.117.欧拉回路