下面的定义都是个人理解
欧拉路:从一个点走到另外一个点,图中每条边都只经过一次
欧拉回路:在欧拉路的基础上,要求终点和起点相同
欧拉路与欧拉回路的判断
对于无向图
- 只有两个点的度数是1,这两个点分别为起点和终点,则这个无向图存在欧拉路
- 每个点的度数都为偶数,则这个无向图存在欧拉回路
对于有向图
- 有一个点的入度比出度多1作为终点,还有一个点的出度比入度多1作为起点,其余点的入度和出度相同,则这个有向图存在欧拉路
- 所有点的入度和出度相同,则这个有向图存在欧拉回路
求欧拉回路
网上都是用的一种dfs的方法,也叫套圆法,名字和算法流程有关
主要流程就是标记走过的点,找到一个环不能往下走时回溯,再通过还没走过的点找另外一个环,把这些环接起来就是欧拉回路,可以用当前弧优化,就是走过这条边之后就不再走了
例题:UOJ #117. 欧拉回路
这就是上面算法的代码实现
其中在加边上用到了一些小技巧,让标记边的时候更方便
#include <bits/stdc++.h>
#define A 1000010
using namespace std;
typedef long long ll;
struct node {int next, to, w;}e[A];
int head[A], num = 1;
void add(int fr, int to, int w) {e[++num].next = head[fr]; e[num].to = to; e[num].w = w; head[fr] = num;}
int t, n, m, a, b, in[A], out[A], cnt, ans[A]; bool vis[A];
void dfs(int fr) {
for (int &i = head[fr]; i; i = e[i].next) {
node t = e[i];
if (vis[i >> 1]) continue;
vis[i >> 1] = 1;
dfs(t.to);
ans[++cnt] = t.w;
}
}
int main(int argc, char const *argv[]) {
cin >> t >> n >> m;
for (int i = 1; i <= m; i++) {
scanf("%d%d", &a, &b);
add(a, b, i); in[b]++; out[a]++;
if (t == 1) add(b, a, -i); else num++;
}
bool ok = 1;
if (t == 1) {
for (int i = 1; i <= n; i++) if ((in[i] + out[i]) % 2) {ok = 0; break;}
}
else for (int i = 1; i <= n; i++) if (in[i] != out[i]) {ok = 0; break;}
if (ok) {
dfs(a);
if (cnt != m) puts("NO");
else {
puts("YES");
for (int i = cnt; i >= 1; i--) printf("%d ", ans[i]);
}
}
else puts("NO");
}