欧拉回路
欧拉回路(一笔画问题)
无向图
度数为奇数的点有0个或2个,0个就是一个欧拉回路,2个就是一个欧拉路径(欧拉回路也是欧拉路径)
有向图
-
欧拉路径:要么所有的点的入度出度,要么除了两个点以外,其余的点的入度出度,剩余的两个点一个满足入度1(起点),一个满足出度1(终点)
-
欧拉回路:所有点的入度==出度
求法:
环可以合并进边, 或者环可以和环合并(类似于绕八字)
对于除了起点和终点之外的点由于他们的度数都是偶数,因此只要从某一个环的出度出发,就一定会走完这个环回到这个点,因此第一次走到头一定是走到了终点
合并环的方法:有环先走环
如果所有的环都集中一个点,那么每次遍历到这个点,都会走m次边,因此复杂度最坏就是$O(m^2)$,所以优化一下
有向图:每用一条边 删掉
无向图:每用一条边标记对应的反向
如果把所有的环都遍历过了,最后遍历到的终点,直接回溯
欧拉回路模板
[link](1184. 欧拉回路 - AcWing题库)
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <set>
#include <queue>
#include <vector>
#include <map>
#include <unordered_map>
#include <cmath>
#include <stack>
#include <iomanip>
#include <deque>
#include <sstream>
#define x first
#define y second
using namespace std;
typedef long double ld;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef unsigned long long ULL;
const int N = 1e5 + 10, M = 2 * N, INF = 0x3f3f3f3f, mod = 1e9 + 7;
const double eps = 1e-8;
int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
int h[N], e[M], ne[M], w[M], idx;
void add(int a, int b, int v = 0) {
e[idx] = b, w[idx] = v, ne[idx] = h[a], h[a] = idx ++;
}
int n, m, k;
bool ok[N];
int res[M], cnt, din[N], dout[N];
int type;
void dfs(int u) {
for (int &i = h[u]; ~i;) {
if (ok[i]) { // 保证这个点用过的边都被删去,否则点会被用很多次,剪枝
i = ne[i];
continue;
}
ok[i] = true; // 表示这个边被遍历了
if (type == 1) ok[i ^ 1] = true; // 小trik无向边两个一定是相邻的,奇偶分布,这样可以快速找到另一个边
int t;
if (type == 1) { // 01 23 45
t = i / 2 + 1; // 找到对应的边的编号 编号从一开始
if (i & 1) t = -t; // 往回走的是负
}
else t = i + 1;
int j = e[i];
i = ne[i]; // 往下一条边
dfs(j); // 回溯回来表示这条边搜的环的加u人了
res[++ cnt] = t; // 将这条边加进去
}
}
int main() {
ios::sync_with_stdio(false), cin.tie(0);
memset(h, -1, sizeof h);
cin >> type >> n >> m;
for (int i = 0; i < m; i ++ ) {
int a, b;
cin >> a >> b;
add(a, b);
if (type == 1) add(b, a);
din[b] ++, dout[a] ++;
}
if (type == 1) {
for (int i = 1; i <= n; i ++ )
if (din[i] + dout[i] & 1) {
cout << "NO" << endl;
return 0;
}
}
else {
for (int i = 1; i<= n; i ++ )
if (din[i] != dout[i]) {
cout << "NO" << endl;
return 0;
}
}
for (int i = 1; i <= n; i ++ )
if (h[i] != -1) { // 找一个起点
dfs(i);
break;
}
if (cnt < m) {
cout << "NO" << endl;
return 0;
}
cout << "YES" << endl;
for (int i = cnt; i; i -- ) cout << res[i] << ' ';
cout << endl;
return 0;
}