欧拉回路模板

模板题:欧拉回路(含有向图和无向图)

未优化版:复杂度又可能会超过O(m),原因是把当前边删掉后,只有子节点会受影响,而它的父节点会继续遍历被删去的边,例如在1个点,很多自环的例子中会被卡

#include<bits/stdc++.h>
#define LL long long
#define x first
#define y second
using namespace std;
typedef pair<int, int> PII;
int t;
const int N = 1e5 + 10, M = 4e5 + 10;
int h[N], e[M], ne[M], idx;
void add(int a, int b) {
	ne[idx] = h[a], e[idx] = b, h[a] = idx++;
}
int n, m;
int din[N], dout[N];
bool st[M];//每条边是否被访问过
int cnt;//一共访问了几条边
int res[M / 2];//欧拉回路dfs后保存的是逆序
void dfs(int u) {
	for (int i = h[u]; ~i; i = ne[i]) {
		int j = e[i];
		if (st[i]) {
			h[u] = ne[i];
			continue;
		}
		h[u] = ne[i];
		st[i] = true;
		if (t == 1)st[i ^ 1] = true;
		dfs(j);//先dfs所有子节点,再加入当前的节点到res数组中
		cnt++;
		if (t == 1) {
			if (i & 1) {
				res[cnt] = -(i / 2 + 1);
			}
			else {
				res[cnt] = i / 2 + 1;
			}
		}
		else {
			res[cnt] = i+1;
		}
	}

}
int main() {
	freopen("in.in", "r", stdin);
	memset(h, -1, sizeof h);
	cin >> t;
	cin >> n >> m;
	for (int i = 1; i <= m; i++) {
		int a, b;
		cin >> a >> b;
		add(a, b);
		dout[a]++, din[b]++;
		if (t == 1)add(b, a);
	}
	if (t == 1) {
		for(int i=1;i<=n;i++)
			if ((din[i] + dout[i]) & 1) {//这里是为了取巧,把无向图“所有节点的度是偶数”,变成“入度”和“出度”相加是偶数
				puts("NO");
				return 0;
			}
	}
	else {
		for (int i = 1; i <= n; i++) {
			if (din[i] != dout[i]) {
				puts("NO");
				return 0;
			}
		}
	}
	for (int i = 1; i <= n; i++) {
		if (h[i] != -1) {//注意是要选第一个不是孤立点的点
			dfs(i);
			break;
		}
	}
	if (cnt < m)puts("NO");
	else {
		puts("YES");
		for (int i = m; i; i--) {
			cout << res[i] << " ";
		}
	}

}

优化做法:

把i保存为h[u]的地址,在边被删除时,它的父节点的i会自动变成当前未被访问过的边,而不会再重复遍历同一条边,可以把复杂度优化到准确的O(m)

#include<bits/stdc++.h>
#define LL long long
#define x first
#define y second
using namespace std;
typedef pair<int, int> PII;
int t;
const int N = 1e5 + 10, M = 4e5 + 10;
int h[N], e[M], ne[M], idx;
void add(int a, int b) {
	ne[idx] = h[a], e[idx] = b, h[a] = idx++;
}
int n, m;
int din[N], dout[N];
bool st[M];
int cnt;
int res[M / 2];
void dfs(int u) {
	for (int& i = h[u]; ~i; ) {//&i=h[u]
		int j = e[i];
		if (st[i]) {
			i = ne[i];
			continue;
		}
		st[i] = true;
		if (t == 1)st[i ^ 1] = true;
		
		int tmp_ans;
		if (t == 1) {
			if (i & 1) {
				tmp_ans = -(i / 2 + 1);
			}
			else {
				tmp_ans = i / 2 + 1;
			}
		}
		else {
			tmp_ans = i + 1;
		}
		i = ne[i];
		dfs(j);
		res[++cnt]=tmp_ans;
		
	}

}
int main() {
	freopen("in.in", "r", stdin);
	memset(h, -1, sizeof h);
	cin >> t;
	cin >> n >> m;
	for (int i = 1; i <= m; i++) {
		int a, b;
		cin >> a >> b;
		add(a, b);
		dout[a]++, din[b]++;
		if (t == 1)add(b, a);
	}
	if (t == 1) {
		for(int i=1;i<=n;i++)
			if ((din[i] + dout[i]) & 1) {
				puts("NO");
				return 0;
			}
	}
	else {
		for (int i = 1; i <= n; i++) {
			if (din[i] != dout[i]) {
				puts("NO");
				return 0;
			}
		}
	}
	for (int i = 1; i <= n; i++) {
		if (h[i] != -1) {
			dfs(i);
			break;
		}
	}
	if (cnt < m)puts("NO");
	else {
		puts("YES");
		for (int i = m; i; i--) {
			cout << res[i] << " ";
		}
	}

}