1184. 欧拉回路(欧拉回路,模板题)

活动 - AcWing

给定一张图,请你找出欧拉回路,即在图中找一个环使得每条边都在环上出现恰好一次。

输入格式

第一行包含一个整数 t,t∈{1,2},如果 t=1,表示所给图为无向图,如果 t=2,表示所给图为有向图。

第二行包含两个整数 n,m,表示图的结点数和边数。

接下来 m 行中,第 i 行两个整数 vi,ui,表示第 i 条边(从 11 开始编号)。

  • 如果 t=1 则表示 vi 到 ui 有一条无向边。
  • 如果 t=2 则表示 vi 到 ui 有一条有向边。

图中可能有重边也可能有自环。

点的编号从 1 到 n。

输出格式

如果无法一笔画出欧拉回路,则输出一行:NO。

否则,输出一行:YES,接下来一行输出 任意一组 合法方案即可。

  • 如果 t=1,输出 m 个整数 p1,p2,…,pm。令 e=|pi|,那么 e 表示经过的第 i 条边的编号。如果 pi 为正数表示从 ve 走到 ue,否则表示从 ue 走到 ve。
  • 如果 t=2,输出 m 个整数 p1,p2,…,pm。其中 pi 表示经过的第 i 条边的编号。
数据范围

1≤n≤105
0≤m≤2×105

输入样例1:
1
3 3
1 2
2 3
1 3
输出样例1:
YES
1 2 -3
输入样例2:
2
5 6
2 3
2 5
3 4
1 2
4 2
5 1
输出样例2:
YES
4 1 3 5 2 6

解析: 

一、在无向图中(所有边都是连通的): 

(1)存在欧拉路径的充分必要条件:度数为奇数的点只能有0或2。 

(2)存在欧拉回路(起点和终点相同)的充分必要条件:度数为奇数的点只能有0个。 

二、在有向图中(所有边都是连通的): 

(1)存在欧拉路径的充分必要条件:要么所有点的入度均等于入度;要么除了两个点之外,其余所有的点的出度等于入度,剩余的两个点:一个满足出度比入度多1(起点),另一个满足入度比出度多1(终点)。 

(2)存在欧拉回路(起点和终点相同)的充分必要条件:所有点的入度均等于出度。 

欧拉回路的dfs用边来判重,不能用点。 

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair PII;
const int N = 1e5 + 5, M = 4e5 + 5, INF = 0x3f3f3f3f;

int n, m;
int h[N], e[M], ne[M], idx;
int din[N], dout[N];
int ans[M], cnt;
bool used[M];
int type;

void add(int a, int b) {
	e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}

void dfs(int u) {
	//cout << "_______________________" << u << endl;
	for (int& i = h[u]; i != -1;) {
		if (used[i]) {
			i = ne[i];
			continue;
		}
		int t;
		if (type == 1) {
			t = i / 2 + 1;
			if (i & 1)t = -t;
		}
		else t = i + 1;
		used[i] = 1;
		if (type == 1) {
			used[i ^ 1] = 1;
		}
		int j = e[i];
		i = ne[i];
		dfs(j);
		ans[++cnt] = t;
	}
}

int main() {
	cin >> type;
	cin >> n >> m;
	memset(h, -1, sizeof h);
	for (int i = 1,a,b; i <= m; i++) {
		scanf("%d%d", &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--) {
		printf("%d ", ans[i]);
	}
	return 0;
}

你可能感兴趣的:(#,欧拉回路和欧拉路径,图论)